Skip to content

Commit b06a8db

Browse files
committed
audit the relocations code, and clean it up a little
1 parent 365b90c commit b06a8db

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

src/librustc/mir/interpret/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,9 @@ pub struct Allocation {
496496
/// Note that the bytes of a pointer represent the offset of the pointer
497497
pub bytes: Vec<u8>,
498498
/// Maps from byte addresses to allocations.
499-
/// Only the first byte of a pointer is inserted into the map.
499+
/// Only the first byte of a pointer is inserted into the map; i.e.,
500+
/// every entry in this map applies to `pointer_size` consecutive bytes starting
501+
/// at the given offset.
500502
pub relocations: Relocations,
501503
/// Denotes undefined memory. Reading from undefined memory is forbidden in miri
502504
pub undef_mask: UndefMask,

src/librustc_mir/interpret/memory.rs

+42-22
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
504504
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
505505
/// The last argument controls whether we error out when there are undefined
506506
/// or pointer bytes. You should never call this, call `get_bytes` or
507-
/// `get_bytes_unchecked` instead,
507+
/// `get_bytes_with_undef_and_ptr` instead,
508508
fn get_bytes_internal(
509509
&self,
510510
ptr: Pointer,
@@ -519,9 +519,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
519519

520520
if check_defined_and_ptr {
521521
self.check_defined(ptr, size)?;
522-
if self.relocations(ptr, size)?.len() != 0 {
523-
return err!(ReadPointerAsBytes);
524-
}
522+
self.check_relocations(ptr, size)?;
523+
} else {
524+
// We still don't want relocations on the *edges*
525+
self.check_relocation_edges(ptr, size)?;
525526
}
526527

527528
let alloc = self.get(ptr.alloc_id)?;
@@ -537,6 +538,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
537538
}
538539

539540
/// It is the caller's responsibility to handle undefined and pointer bytes.
541+
/// However, this still checks that there are no relocations on the egdes.
540542
#[inline]
541543
fn get_bytes_with_undef_and_ptr(
542544
&self,
@@ -547,6 +549,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
547549
self.get_bytes_internal(ptr, size, align, false)
548550
}
549551

552+
/// Just calling this already marks everything as defined and removes relocations,
553+
/// so be sure to actually put data there!
550554
fn get_bytes_mut(
551555
&mut self,
552556
ptr: Pointer,
@@ -654,11 +658,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
654658
}
655659
let src = src.to_ptr()?;
656660
let dest = dest.to_ptr()?;
657-
self.check_relocation_edges(src, size)?;
658661

659662
// first copy the relocations to a temporary buffer, because
660663
// `get_bytes_mut` will clear the relocations, which is correct,
661664
// since we don't want to keep any relocations at the target.
665+
// (`get_bytes_with_undef_and_ptr` below checks that there are no
666+
// relocations overlapping the edges; those would not be handled correctly).
662667
let relocations = {
663668
let relocations = self.relocations(src, size)?;
664669
let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
@@ -676,7 +681,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
676681
new_relocations
677682
};
678683

679-
// This also checks alignment.
684+
// This also checks alignment, and relocation edges on the src.
680685
let src_bytes = self.get_bytes_with_undef_and_ptr(src, size, src_align)?.as_ptr();
681686
let dest_bytes = self.get_bytes_mut(dest, size * length, dest_align)?.as_mut_ptr();
682687

@@ -710,8 +715,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
710715
}
711716
}
712717

718+
// copy definedness to the destination
713719
self.copy_undef_mask(src, dest, size, length)?;
714-
// copy back the relocations
720+
// copy the relocations to the destination
715721
self.get_mut(dest.alloc_id)?.relocations.insert_presorted(relocations);
716722

717723
Ok(())
@@ -724,9 +730,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
724730
match alloc.bytes[offset..].iter().position(|&c| c == 0) {
725731
Some(size) => {
726732
let p1 = Size::from_bytes((size + 1) as u64);
727-
if self.relocations(ptr, p1)?.len() != 0 {
728-
return err!(ReadPointerAsBytes);
729-
}
733+
self.check_relocations(ptr, p1)?;
730734
self.check_defined(ptr, p1)?;
731735
Ok(&alloc.bytes[offset..offset + size])
732736
}
@@ -777,9 +781,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
777781
ptr_align: Align,
778782
size: Size
779783
) -> EvalResult<'tcx, ScalarMaybeUndef> {
780-
// Make sure we don't read part of a pointer as a pointer
781-
self.check_relocation_edges(ptr, size)?;
782-
// get_bytes_unchecked tests alignment
784+
// get_bytes_unchecked tests alignment and relocation edges
783785
let bytes = self.get_bytes_with_undef_and_ptr(
784786
ptr, size, ptr_align.min(self.int_align(size))
785787
)?;
@@ -794,9 +796,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
794796
let bits = read_target_uint(self.tcx.data_layout.endian, bytes).unwrap();
795797
// See if we got a pointer
796798
if size != self.pointer_size() {
797-
if self.relocations(ptr, size)?.len() != 0 {
798-
return err!(ReadPointerAsBytes);
799-
}
799+
// *Now* better make sure that the inside also is free of relocations.
800+
self.check_relocations(ptr, size)?;
800801
} else {
801802
let alloc = self.get(ptr.alloc_id)?;
802803
match alloc.relocations.get(&ptr.offset) {
@@ -887,16 +888,35 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
887888

888889
/// Relocations
889890
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
891+
/// Return all relocations overlapping with the given ptr-offset pair.
890892
fn relocations(
891893
&self,
892894
ptr: Pointer,
893895
size: Size,
894896
) -> EvalResult<'tcx, &[(Size, AllocId)]> {
897+
// We have to go back `pointer_size - 1` bytes, as that one would still overlap with
898+
// the beginning of this range.
895899
let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
896-
let end = ptr.offset + size;
900+
let end = ptr.offset + size; // this does overflow checking
897901
Ok(self.get(ptr.alloc_id)?.relocations.range(Size::from_bytes(start)..end))
898902
}
899903

904+
/// Check that there ar eno relocations overlapping with the given range.
905+
#[inline(always)]
906+
fn check_relocations(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
907+
if self.relocations(ptr, size)?.len() != 0 {
908+
err!(ReadPointerAsBytes)
909+
} else {
910+
Ok(())
911+
}
912+
}
913+
914+
/// Remove all relocations inside the given range.
915+
/// If there are relocations overlapping with the edges, they
916+
/// are removed as well *and* the bytes they cover are marked as
917+
/// uninitialized. This is a somewhat odd "spooky action at a distance",
918+
/// but it allows strictly more code to run than if we would just error
919+
/// immediately in that case.
900920
fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
901921
// Find the start and end of the given range and its outermost relocations.
902922
let (first, last) = {
@@ -929,12 +949,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
929949
Ok(())
930950
}
931951

952+
/// Error if there are relocations overlapping with the egdes of the
953+
/// given memory range.
954+
#[inline]
932955
fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
933-
let overlapping_start = self.relocations(ptr, Size::ZERO)?.len();
934-
let overlapping_end = self.relocations(ptr.offset(size, self)?, Size::ZERO)?.len();
935-
if overlapping_start + overlapping_end != 0 {
936-
return err!(ReadPointerAsBytes);
937-
}
956+
self.check_relocations(ptr, Size::ZERO)?;
957+
self.check_relocations(ptr.offset(size, self)?, Size::ZERO)?;
938958
Ok(())
939959
}
940960
}

0 commit comments

Comments
 (0)