Skip to content

Commit 07d1835

Browse files
committed
const-eval: fix and re-enable pointer fragment support
1 parent 907705a commit 07d1835

File tree

16 files changed

+326
-306
lines changed

16 files changed

+326
-306
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,14 +1498,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14981498

14991499
// Prepare getting source provenance.
15001500
let src_bytes = src_alloc.get_bytes_unchecked(src_range).as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
1501-
// first copy the provenance to a temporary buffer, because
1502-
// `get_bytes_mut` will clear the provenance, which is correct,
1503-
// since we don't want to keep any provenance at the target.
1504-
// This will also error if copying partial provenance is not supported.
1505-
let provenance = src_alloc
1506-
.provenance()
1507-
.prepare_copy(src_range, self)
1508-
.map_err(|e| e.to_interp_error(src_alloc_id))?;
1501+
// First copy the provenance to a temporary buffer, because
1502+
// `get_bytes_unchecked_for_overwrite_ptr` will clear the provenance (in preparation for
1503+
// inserting the new provenance), and that can overlap with the source range.
1504+
let provenance = src_alloc.provenance_prepare_copy(src_range, self);
15091505
// Prepare a copy of the initialization mask.
15101506
let init = src_alloc.init_mask().prepare_copy(src_range);
15111507

compiler/rustc_middle/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#![feature(negative_impls)]
5252
#![feature(never_type)]
5353
#![feature(ptr_alignment_type)]
54+
#![feature(range_bounds_is_empty)]
5455
#![feature(rustc_attrs)]
5556
#![feature(rustdoc_internals)]
5657
#![feature(sized_hierarchy)]

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

Lines changed: 28 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ use rustc_macros::HashStable;
1919
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
2020

2121
use super::{
22-
AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer,
23-
PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
24-
UndefinedBehaviorInfo, UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint,
22+
AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer, Provenance,
23+
ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo,
24+
interp_ok, read_target_uint, write_target_uint,
2525
};
2626
use crate::ty;
2727

@@ -601,14 +601,13 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
601601
})?;
602602
if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) {
603603
// Find the provenance.
604-
let (offset, _prov) = self
604+
let (prov_range, _prov) = self
605605
.provenance
606-
.range_ptrs_get(range, cx)
607-
.first()
608-
.copied()
606+
.get_range(range, cx)
607+
.next()
609608
.expect("there must be provenance somewhere here");
610-
let start = offset.max(range.start); // the pointer might begin before `range`!
611-
let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`!
609+
let start = prov_range.start.max(range.start); // the pointer might begin before `range`!
610+
let end = prov_range.end().min(range.end()); // the pointer might end after `range`!
612611
return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {
613612
access: range,
614613
bad: AllocRange::from(start..end),
@@ -630,7 +629,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
630629
range: AllocRange,
631630
) -> &mut [u8] {
632631
self.mark_init(range, true);
633-
self.provenance.clear(range, cx);
632+
self.provenance.clear(range, &self.bytes, cx);
634633

635634
&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
636635
}
@@ -643,7 +642,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
643642
range: AllocRange,
644643
) -> *mut [u8] {
645644
self.mark_init(range, true);
646-
self.provenance.clear(range, cx);
645+
self.provenance.clear(range, &self.bytes, cx);
647646

648647
assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
649648
// Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`.
@@ -711,57 +710,14 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
711710
if read_provenance {
712711
assert_eq!(range.size, cx.data_layout().pointer_size());
713712

714-
// When reading data with provenance, the easy case is finding provenance exactly where we
715-
// are reading, then we can put data and provenance back together and return that.
716-
if let Some(prov) = self.provenance.get_ptr(range.start) {
717-
// Now we can return the bits, with their appropriate provenance.
713+
if let Some(prov) = self.provenance.read_ptr(range.start, cx)? {
714+
// Assemble the bits with their provenance.
718715
let ptr = Pointer::new(prov, Size::from_bytes(bits));
719-
return Ok(Scalar::from_pointer(ptr, cx));
716+
Ok(Scalar::from_pointer(ptr, cx))
717+
} else {
718+
// Return raw bits without provenance.
719+
Ok(Scalar::from_uint(bits, range.size))
720720
}
721-
// The other easy case is total absence of provenance.
722-
if self.provenance.range_empty(range, cx) {
723-
return Ok(Scalar::from_uint(bits, range.size));
724-
}
725-
// If we get here, we have to check per-byte provenance, and join them together.
726-
let prov = 'prov: {
727-
if !Prov::OFFSET_IS_ADDR {
728-
// FIXME(#146291): We need to ensure that we don't mix different pointers with
729-
// the same provenance.
730-
return Err(AllocError::ReadPartialPointer(range.start));
731-
}
732-
// Initialize with first fragment. Must have index 0.
733-
let Some((mut joint_prov, 0)) = self.provenance.get_byte(range.start, cx) else {
734-
break 'prov None;
735-
};
736-
// Update with the remaining fragments.
737-
for offset in Size::from_bytes(1)..range.size {
738-
// Ensure there is provenance here and it has the right index.
739-
let Some((frag_prov, frag_idx)) =
740-
self.provenance.get_byte(range.start + offset, cx)
741-
else {
742-
break 'prov None;
743-
};
744-
// Wildcard provenance is allowed to come with any index (this is needed
745-
// for Miri's native-lib mode to work).
746-
if u64::from(frag_idx) != offset.bytes() && Some(frag_prov) != Prov::WILDCARD {
747-
break 'prov None;
748-
}
749-
// Merge this byte's provenance with the previous ones.
750-
joint_prov = match Prov::join(joint_prov, frag_prov) {
751-
Some(prov) => prov,
752-
None => break 'prov None,
753-
};
754-
}
755-
break 'prov Some(joint_prov);
756-
};
757-
if prov.is_none() && !Prov::OFFSET_IS_ADDR {
758-
// There are some bytes with provenance here but overall the provenance does not add up.
759-
// We need `OFFSET_IS_ADDR` to fall back to no-provenance here; without that option, we must error.
760-
return Err(AllocError::ReadPartialPointer(range.start));
761-
}
762-
// We can use this provenance.
763-
let ptr = Pointer::new(prov, Size::from_bytes(bits));
764-
return Ok(Scalar::from_maybe_pointer(ptr, cx));
765721
} else {
766722
// We are *not* reading a pointer.
767723
// If we can just ignore provenance or there is none, that's easy.
@@ -816,7 +772,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
816772
/// Write "uninit" to the given memory range.
817773
pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
818774
self.mark_init(range, false);
819-
self.provenance.clear(range, cx);
775+
self.provenance.clear(range, &self.bytes, cx);
820776
}
821777

822778
/// Mark all bytes in the given range as initialised and reset the provenance
@@ -831,21 +787,28 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
831787
size: Size::from_bytes(self.len()),
832788
});
833789
self.mark_init(range, true);
834-
self.provenance.write_wildcards(cx, range);
790+
self.provenance.write_wildcards(cx, &self.bytes, range);
835791
}
836792

837793
/// Remove all provenance in the given memory range.
838794
pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
839-
self.provenance.clear(range, cx);
795+
self.provenance.clear(range, &self.bytes, cx);
840796
}
841797

842798
pub fn provenance_merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
843799
self.provenance.merge_bytes(cx)
844800
}
845801

802+
pub fn provenance_prepare_copy(
803+
&self,
804+
range: AllocRange,
805+
cx: &impl HasDataLayout,
806+
) -> ProvenanceCopy<Prov> {
807+
self.provenance.prepare_copy(range, &self.bytes, cx)
808+
}
809+
846810
/// Applies a previously prepared provenance copy.
847-
/// The affected range, as defined in the parameters to `provenance().prepare_copy` is expected
848-
/// to be clear of provenance.
811+
/// The affected range is expected to be clear of provenance.
849812
///
850813
/// This is dangerous to use as it can violate internal `Allocation` invariants!
851814
/// It only exists to support an efficient implementation of `mem_copy_repeatedly`.

0 commit comments

Comments
 (0)