Store allocation size, make bytes, undef_mask private
Direct access to the bytes was previously a problem (#62931) where components would read their contents without properly checking relocations and/or definedness. Making bytes private instead of purely renaming them also helps in allowing amendments to their allocation scheme (such as eliding allocation for undef of constant regions).
This commit is contained in:
parent
c43d03a19f
commit
9b9eecf964
3 changed files with 42 additions and 11 deletions
|
|
@ -176,15 +176,21 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
|
|||
hasher: &mut StableHasher<W>,
|
||||
) {
|
||||
let mir::interpret::Allocation {
|
||||
bytes, relocations, undef_mask, align, mutability,
|
||||
relocations, align, mutability, size,
|
||||
extra: _,
|
||||
.. /* private bytes and undef_mask */
|
||||
} = self;
|
||||
|
||||
let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(0..self.len());
|
||||
let undef_mask = self.undef_mask();
|
||||
|
||||
bytes.hash_stable(hcx, hasher);
|
||||
relocations.len().hash_stable(hcx, hasher);
|
||||
for reloc in relocations.iter() {
|
||||
reloc.hash_stable(hcx, hasher);
|
||||
}
|
||||
undef_mask.hash_stable(hcx, hasher);
|
||||
size.hash_stable(hcx, hasher);
|
||||
align.hash_stable(hcx, hasher);
|
||||
mutability.hash_stable(hcx, hasher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,17 @@ use std::borrow::Cow;
|
|||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Allocation<Tag=(),Extra=()> {
|
||||
/// The actual bytes of the allocation.
|
||||
/// Note that the bytes of a pointer represent the offset of the pointer
|
||||
pub bytes: Vec<u8>,
|
||||
/// Note that the bytes of a pointer represent the offset of the pointer.
|
||||
bytes: Vec<u8>,
|
||||
/// Maps from byte addresses to extra data for each pointer.
|
||||
/// Only the first byte of a pointer is inserted into the map; i.e.,
|
||||
/// every entry in this map applies to `pointer_size` consecutive bytes starting
|
||||
/// at the given offset.
|
||||
pub relocations: Relocations<Tag>,
|
||||
/// Denotes undefined memory. Reading from undefined memory is forbidden in miri
|
||||
pub undef_mask: UndefMask,
|
||||
/// Denotes which part of this allocation is initialized.
|
||||
undef_mask: UndefMask,
|
||||
/// The size of the allocation. Currently, must always equal `bytes.len()`.
|
||||
pub size: Size,
|
||||
/// The alignment of the allocation to detect unaligned reads.
|
||||
pub align: Align,
|
||||
/// Whether the allocation is mutable.
|
||||
|
|
@ -85,11 +87,12 @@ impl<Tag> Allocation<Tag> {
|
|||
/// Creates a read-only allocation initialized by the given bytes
|
||||
pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
|
||||
let bytes = slice.into().into_owned();
|
||||
let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true);
|
||||
let size = Size::from_bytes(bytes.len() as u64);
|
||||
Self {
|
||||
bytes,
|
||||
relocations: Relocations::new(),
|
||||
undef_mask,
|
||||
undef_mask: UndefMask::new(size, true),
|
||||
size,
|
||||
align,
|
||||
mutability: Mutability::Immutable,
|
||||
extra: (),
|
||||
|
|
@ -106,6 +109,7 @@ impl<Tag> Allocation<Tag> {
|
|||
bytes: vec![0; size.bytes() as usize],
|
||||
relocations: Relocations::new(),
|
||||
undef_mask: UndefMask::new(size, false),
|
||||
size,
|
||||
align,
|
||||
mutability: Mutability::Mutable,
|
||||
extra: (),
|
||||
|
|
@ -113,6 +117,21 @@ impl<Tag> Allocation<Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Raw accessors. Provide access to otherwise private bytes.
|
||||
impl<Tag, Extra> Allocation<Tag, Extra> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.size.bytes() as usize
|
||||
}
|
||||
|
||||
/// Look at a slice which may describe undefined bytes or describe a relocation. This differs
|
||||
/// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the
|
||||
/// edges) at all. It further ignores `AllocationExtra` callbacks.
|
||||
/// This must not be used for reads affecting the interpreter execution.
|
||||
pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
|
||||
&self.bytes[range]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {}
|
||||
|
||||
/// Byte accessors
|
||||
|
|
@ -132,9 +151,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
|
|||
);
|
||||
let end = end.bytes() as usize;
|
||||
assert!(
|
||||
end <= self.bytes.len(),
|
||||
end <= self.len(),
|
||||
"Out-of-bounds access at offset {}, size {} in allocation of size {}",
|
||||
offset.bytes(), size.bytes(), self.bytes.len()
|
||||
offset.bytes(), size.bytes(), self.len()
|
||||
);
|
||||
(offset.bytes() as usize)..end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -944,10 +944,16 @@ pub trait PrettyPrinter<'tcx>:
|
|||
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
|
||||
},
|
||||
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
|
||||
Some(&data.bytes[start..end])
|
||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||
// relocations (we have an active slice reference here). We don't use this
|
||||
// result to affect interpreter execution.
|
||||
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
|
||||
},
|
||||
(ConstValue::Slice { data, start, end }, ty::Str) => {
|
||||
let slice = &data.bytes[start..end];
|
||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||
// relocations (we have an active `str` reference here). We don't use this
|
||||
// result to affect interpreter execution.
|
||||
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
||||
let s = ::std::str::from_utf8(slice)
|
||||
.expect("non utf8 str from miri");
|
||||
p!(write("{:?}", s));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue