1//! The virtual memory representation of the MIR interpreter.
23mod init_mask;
4mod provenance_map;
56use std::alloc::{self, Layout};
7use std::borrow::Cow;
8use std::hash::Hash;
9use std::ops::{Deref, DerefMut, Range};
10use std::{fmt, hash, ptr};
1112use either::{Left, Right};
13use init_mask::*;
14pub use init_mask::{InitChunk, InitChunkIter};
15use provenance_map::*;
16use rustc_abi::{Align, HasDataLayout, Size};
17use rustc_ast::Mutability;
18use rustc_data_structures::intern::Interned;
19use rustc_macros::StableHash;
20use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
2122use super::{
23AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer, Provenance,
24ResourceExhaustionInfo, Scalar, UndefinedBehaviorInfo, UnsupportedOpInfo, interp_ok,
25read_target_uint, write_target_uint,
26};
27use crate::ty;
2829/// Functionality required for the bytes of an `Allocation`.
30pub trait AllocBytes: Clone + fmt::Debug + Deref<Target = [u8]> + DerefMut<Target = [u8]> {
31/// The type of extra parameters passed in when creating an allocation.
32 /// Can be used by `interpret::Machine` instances to make runtime-configuration-dependent
33 /// decisions about the allocation strategy.
34type AllocParams;
3536/// Create an `AllocBytes` from a slice of `u8`.
37fn from_bytes<'a>(
38 slice: impl Into<Cow<'a, [u8]>>,
39 _align: Align,
40 _params: Self::AllocParams,
41 ) -> Self;
4243/// Create a zeroed `AllocBytes` of the specified size and alignment.
44 /// Returns `None` if we ran out of memory on the host.
45fn zeroed(size: Size, _align: Align, _params: Self::AllocParams) -> Option<Self>;
4647/// Gives direct access to the raw underlying storage.
48 ///
49 /// Crucially this pointer is compatible with:
50 /// - other pointers returned by this method, and
51 /// - references returned from `deref()`, as long as there was no write.
52fn as_mut_ptr(&mut self) -> *mut u8;
5354/// Gives direct access to the raw underlying storage.
55 ///
56 /// Crucially this pointer is compatible with:
57 /// - other pointers returned by this method, and
58 /// - references returned from `deref()`, as long as there was no write.
59fn as_ptr(&self) -> *const u8;
60}
6162/// Default `bytes` for `Allocation` is a `Box<u8>`.
63impl AllocBytesfor Box<[u8]> {
64type AllocParams = ();
6566fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align, _params: ()) -> Self {
67Box::<[u8]>::from(slice.into())
68 }
6970fn zeroed(size: Size, _align: Align, _params: ()) -> Option<Self> {
71let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?;
72// SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
73let bytes = unsafe { bytes.assume_init() };
74Some(bytes)
75 }
7677fn as_mut_ptr(&mut self) -> *mut u8 {
78Box::as_mut_ptr(self).cast()
79 }
8081fn as_ptr(&self) -> *const u8 {
82Box::as_ptr(self).cast()
83 }
84}
8586/// This type represents an Allocation in the Miri/CTFE core engine.
87///
88/// Its public API is rather low-level, working directly with allocation offsets and a custom error
89/// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory`
90/// module provides higher-level access.
91// Note: for performance reasons when interning, some of the `Allocation` fields can be partially
92// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
93#[derive(#[automatically_derived]
impl<Prov: ::core::clone::Clone + Provenance, Extra: ::core::clone::Clone,
Bytes: ::core::clone::Clone> ::core::clone::Clone for
Allocation<Prov, Extra, Bytes> {
#[inline]
fn clone(&self) -> Allocation<Prov, Extra, Bytes> {
Allocation {
bytes: ::core::clone::Clone::clone(&self.bytes),
provenance: ::core::clone::Clone::clone(&self.provenance),
init_mask: ::core::clone::Clone::clone(&self.init_mask),
align: ::core::clone::Clone::clone(&self.align),
mutability: ::core::clone::Clone::clone(&self.mutability),
extra: ::core::clone::Clone::clone(&self.extra),
}
}
}Clone, #[automatically_derived]
impl<Prov: ::core::cmp::Eq + Provenance, Extra: ::core::cmp::Eq,
Bytes: ::core::cmp::Eq> ::core::cmp::Eq for Allocation<Prov, Extra, Bytes>
{
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Bytes>;
let _: ::core::cmp::AssertParamIsEq<ProvenanceMap<Prov>>;
let _: ::core::cmp::AssertParamIsEq<InitMask>;
let _: ::core::cmp::AssertParamIsEq<Align>;
let _: ::core::cmp::AssertParamIsEq<Mutability>;
let _: ::core::cmp::AssertParamIsEq<Extra>;
}
}Eq, #[automatically_derived]
impl<Prov: ::core::cmp::PartialEq + Provenance, Extra: ::core::cmp::PartialEq,
Bytes: ::core::cmp::PartialEq> ::core::cmp::PartialEq for
Allocation<Prov, Extra, Bytes> {
#[inline]
fn eq(&self, other: &Allocation<Prov, Extra, Bytes>) -> bool {
self.bytes == other.bytes && self.provenance == other.provenance &&
self.init_mask == other.init_mask &&
self.align == other.align &&
self.mutability == other.mutability &&
self.extra == other.extra
}
}PartialEq)]
94#[derive(const _: () =
{
impl<Prov: Provenance, Extra, Bytes>
::rustc_data_structures::stable_hash::StableHash for
Allocation<Prov, Extra, Bytes> where
Bytes: ::rustc_data_structures::stable_hash::StableHash,
Prov: ::rustc_data_structures::stable_hash::StableHash,
Extra: ::rustc_data_structures::stable_hash::StableHash {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
Allocation {
bytes: ref __binding_0,
provenance: ref __binding_1,
init_mask: ref __binding_2,
align: ref __binding_3,
mutability: ref __binding_4,
extra: ref __binding_5 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
{ __binding_3.stable_hash(__hcx, __hasher); }
{ __binding_4.stable_hash(__hcx, __hasher); }
{ __binding_5.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
95pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> {
96/// The actual bytes of the allocation.
97 /// Note that the bytes of a pointer represent the offset of the pointer.
98bytes: Bytes,
99/// Maps from byte addresses to extra provenance data for each pointer.
100 /// Only the first byte of a pointer is inserted into the map; i.e.,
101 /// every entry in this map applies to `pointer_size` consecutive bytes starting
102 /// at the given offset.
103provenance: ProvenanceMap<Prov>,
104/// Denotes which part of this allocation is initialized.
105 ///
106 /// Invariant: the uninitialized parts have no provenance.
107init_mask: InitMask,
108/// The alignment of the allocation to detect unaligned reads.
109 /// (`Align` guarantees that this is a power of two.)
110pub align: Align,
111/// `true` if the allocation is mutable.
112 /// Also used by codegen to determine if a static should be put into mutable memory,
113 /// which happens for `static mut` and `static` with interior mutability.
114pub mutability: Mutability,
115/// Extra state for the machine.
116pub extra: Extra,
117}
118119/// Helper struct that packs an alignment, mutability, and "all bytes are zero" flag together.
120///
121/// Alignment values always have 2 free high bits, and we check for this in our [`Encodable`] impl.
122struct AllocFlags {
123 align: Align,
124 mutability: Mutability,
125 all_zero: bool,
126}
127128impl<E: Encoder> Encodable<E> for AllocFlags {
129fn encode(&self, encoder: &mut E) {
130// Make sure Align::MAX can be stored with the high 2 bits unset.
131const {
132let max_supported_align_repr = u8::MAX >> 2;
133let max_supported_align = 1 << max_supported_align_repr;
134if !(Align::MAX.bytes() <= max_supported_align) {
::core::panicking::panic("assertion failed: Align::MAX.bytes() <= max_supported_align")
}assert!(Align::MAX.bytes() <= max_supported_align)135 }
136137let mut flags = self.align.bytes().trailing_zeros() as u8;
138flags |= match self.mutability {
139 Mutability::Not => 0,
140 Mutability::Mut => 1 << 6,
141 };
142flags |= (self.all_zero as u8) << 7;
143flags.encode(encoder);
144 }
145}
146147impl<D: Decoder> Decodable<D> for AllocFlags {
148fn decode(decoder: &mut D) -> Self {
149let flags: u8 = Decodable::decode(decoder);
150let align = flags & 0b0011_1111;
151let mutability = flags & 0b0100_0000;
152let all_zero = flags & 0b1000_0000;
153154let align = Align::from_bytes(1 << align).unwrap();
155let mutability = match mutability {
1560 => Mutability::Not,
157_ => Mutability::Mut,
158 };
159let all_zero = all_zero > 0;
160161AllocFlags { align, mutability, all_zero }
162 }
163}
164165/// Efficiently detect whether a slice of `u8` is all zero.
166///
167/// This is used in encoding of [`Allocation`] to special-case all-zero allocations. It is only
168/// optimized a little, because for many allocations the encoding of the actual bytes does not
169/// dominate runtime.
170#[inline]
171fn all_zero(buf: &[u8]) -> bool {
172// In the empty case we wouldn't encode any contents even without this system where we
173 // special-case allocations whose contents are all 0. We can return anything in the empty case.
174if buf.is_empty() {
175return true;
176 }
177// Just fast-rejecting based on the first element significantly reduces the amount that we end
178 // up walking the whole array.
179if buf[0] != 0 {
180return false;
181 }
182183// This strategy of combining all slice elements with & or | is unbeatable for the large
184 // all-zero case because it is so well-understood by autovectorization.
185buf.iter().fold(true, |acc, b| acc & (*b == 0))
186}
187188/// Custom encoder for [`Allocation`] to more efficiently represent the case where all bytes are 0.
189impl<Prov: Provenance, Extra, E: Encoder> Encodable<E> for Allocation<Prov, Extra, Box<[u8]>>
190where
191ProvenanceMap<Prov>: Encodable<E>,
192 Extra: Encodable<E>,
193{
194fn encode(&self, encoder: &mut E) {
195let all_zero = all_zero(&self.bytes);
196AllocFlags { align: self.align, mutability: self.mutability, all_zero }.encode(encoder);
197198encoder.emit_usize(self.bytes.len());
199if !all_zero {
200encoder.emit_raw_bytes(&self.bytes);
201 }
202self.provenance.encode(encoder);
203self.init_mask.encode(encoder);
204self.extra.encode(encoder);
205 }
206}
207208impl<Prov: Provenance, Extra, D: Decoder> Decodable<D> for Allocation<Prov, Extra, Box<[u8]>>
209where
210ProvenanceMap<Prov>: Decodable<D>,
211 Extra: Decodable<D>,
212{
213fn decode(decoder: &mut D) -> Self {
214let AllocFlags { align, mutability, all_zero } = Decodable::decode(decoder);
215216let len = decoder.read_usize();
217let bytes = if all_zero { ::alloc::vec::from_elem(0u8, len)vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() };
218let bytes = <Box<[u8]> as AllocBytes>::from_bytes(bytes, align, ());
219220let provenance = Decodable::decode(decoder);
221let init_mask = Decodable::decode(decoder);
222let extra = Decodable::decode(decoder);
223224Self { bytes, provenance, init_mask, align, mutability, extra }
225 }
226}
227228/// This is the maximum size we will hash at a time, when interning an `Allocation` and its
229/// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer.
230/// Used when these two structures are large: we only partially hash the larger fields in that
231/// situation. See the comment at the top of their respective `Hash` impl for more details.
232const MAX_BYTES_TO_HASH: usize = 64;
233234/// This is the maximum size (in bytes) for which a buffer will be fully hashed, when interning.
235/// Otherwise, it will be partially hashed in 2 slices, requiring at least 2 `MAX_BYTES_TO_HASH`
236/// bytes.
237const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH;
238239// Const allocations are only hashed for interning. However, they can be large, making the hashing
240// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
241// big buffers like the actual bytes of allocation. We can partially hash some fields when they're
242// large.
243impl hash::Hashfor Allocation {
244fn hash<H: hash::Hasher>(&self, state: &mut H) {
245let Self {
246 bytes,
247 provenance,
248 init_mask,
249 align,
250 mutability,
251 extra: (), // don't bother hashing ()
252} = self;
253254// Partially hash the `bytes` buffer when it is large. To limit collisions with common
255 // prefixes and suffixes, we hash the length and some slices of the buffer.
256let byte_count = bytes.len();
257if byte_count > MAX_HASHED_BUFFER_LEN {
258// Hash the buffer's length.
259byte_count.hash(state);
260261// And its head and tail.
262bytes[..MAX_BYTES_TO_HASH].hash(state);
263bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state);
264 } else {
265bytes.hash(state);
266 }
267268// Hash the other fields as usual.
269provenance.hash(state);
270init_mask.hash(state);
271align.hash(state);
272mutability.hash(state);
273 }
274}
275276/// Interned types generally have an `Outer` type and an `Inner` type, where
277/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
278/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
279/// outer type and `TyKind` is its inner type.
280///
281/// Here things are different because only const allocations are interned. This
282/// means that both the inner type (`Allocation`) and the outer type
283/// (`ConstAllocation`) are used quite a bit.
284#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for ConstAllocation<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for ConstAllocation<'tcx> {
#[inline]
fn clone(&self) -> ConstAllocation<'tcx> {
let _: ::core::clone::AssertParamIsClone<Interned<'tcx, Allocation>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for ConstAllocation<'tcx> {
#[inline]
fn eq(&self, other: &ConstAllocation<'tcx>) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for ConstAllocation<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Interned<'tcx, Allocation>>;
}
}Eq, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for ConstAllocation<'tcx> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, const _: () =
{
impl<'tcx> ::rustc_data_structures::stable_hash::StableHash for
ConstAllocation<'tcx> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
ConstAllocation(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
285#[rustc_pass_by_value]
286pub struct ConstAllocation<'tcx>(pub Interned<'tcx, Allocation>);
287288impl<'tcx> fmt::Debugfor ConstAllocation<'tcx> {
289fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290// The debug representation of this is very verbose and basically useless,
291 // so don't print it.
292f.write_fmt(format_args!("ConstAllocation {{ .. }}"))write!(f, "ConstAllocation {{ .. }}")293 }
294}
295296impl<'tcx> ConstAllocation<'tcx> {
297pub fn inner(self) -> &'tcx Allocation {
298self.0.0
299}
300}
301302/// We have our own error type that does not know about the `AllocId`; that information
303/// is added when converting to `InterpError`.
304#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AllocError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
AllocError::ReadPointerAsInt(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ReadPointerAsInt", &__self_0),
AllocError::ReadPartialPointer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ReadPartialPointer", &__self_0),
AllocError::InvalidUninitBytes(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidUninitBytes", &__self_0),
}
}
}Debug)]
305pub enum AllocError {
306/// Encountered a pointer where we needed raw bytes.
307ReadPointerAsInt(Option<BadBytesAccess>),
308/// Partially copying a pointer.
309ReadPartialPointer(Size),
310/// Using uninitialized data where it is not allowed.
311InvalidUninitBytes(Option<BadBytesAccess>),
312}
313pub type AllocResult<T = ()> = Result<T, AllocError>;
314315impl AllocError {
316pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpErrorKind<'tcx> {
317use AllocError::*;
318match self {
319ReadPointerAsInt(info) => InterpErrorKind::Unsupported(
320 UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))),
321 ),
322ReadPartialPointer(offset) => InterpErrorKind::Unsupported(
323 UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)),
324 ),
325InvalidUninitBytes(info) => InterpErrorKind::UndefinedBehavior(
326 UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
327 ),
328 }
329 }
330}
331332/// The information that makes up a memory access: offset and size.
333#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AllocRange {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "AllocRange",
"start", &self.start, "size", &&self.size)
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for AllocRange { }Copy, #[automatically_derived]
impl ::core::clone::Clone for AllocRange {
#[inline]
fn clone(&self) -> AllocRange {
let _: ::core::clone::AssertParamIsClone<Size>;
*self
}
}Clone)]
334pub struct AllocRange {
335pub start: Size,
336pub size: Size,
337}
338339impl fmt::Displayfor AllocRange {
340fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341f.write_fmt(format_args!("[{0:#x}..{1:#x}]", self.start.bytes(),
self.end().bytes()))write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes())342 }
343}
344345/// Free-starting constructor for less syntactic overhead.
346#[inline(always)]
347pub fn alloc_range(start: Size, size: Size) -> AllocRange {
348AllocRange { start, size }
349}
350351impl From<Range<Size>> for AllocRange {
352#[inline]
353fn from(r: Range<Size>) -> Self {
354alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
355}
356}
357358impl From<Range<usize>> for AllocRange {
359#[inline]
360fn from(r: Range<usize>) -> Self {
361AllocRange::from(Size::from_bytes(r.start)..Size::from_bytes(r.end))
362 }
363}
364365impl AllocRange {
366#[inline(always)]
367pub fn end(self) -> Size {
368self.start + self.size // This does overflow checking.
369}
370371/// Returns the `subrange` within this range; panics if it is not a subrange.
372#[inline]
373pub fn subrange(self, subrange: AllocRange) -> AllocRange {
374let sub_start = self.start + subrange.start;
375let range = alloc_range(sub_start, subrange.size);
376if !(range.end() <= self.end()) {
{
::core::panicking::panic_fmt(format_args!("access outside the bounds for given AllocRange"));
}
};assert!(range.end() <= self.end(), "access outside the bounds for given AllocRange");
377range378 }
379}
380381/// Whether a new allocation should be initialized with zero-bytes.
382pub enum AllocInit {
383 Uninit,
384 Zero,
385}
386387// The constructors are all without extra; the extra gets added by a machine hook later.
388impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
389/// Creates an allocation initialized by the given bytes
390pub fn from_bytes<'a>(
391 slice: impl Into<Cow<'a, [u8]>>,
392 align: Align,
393 mutability: Mutability,
394 params: <Bytes as AllocBytes>::AllocParams,
395 ) -> Self {
396let bytes = Bytes::from_bytes(slice, align, params);
397let size = Size::from_bytes(bytes.len());
398Self {
399bytes,
400 provenance: ProvenanceMap::new(),
401 init_mask: InitMask::new(size, true),
402align,
403mutability,
404 extra: (),
405 }
406 }
407408pub fn from_bytes_byte_aligned_immutable<'a>(
409 slice: impl Into<Cow<'a, [u8]>>,
410 params: <Bytes as AllocBytes>::AllocParams,
411 ) -> Self {
412Allocation::from_bytes(slice, Align::ONE, Mutability::Not, params)
413 }
414415fn new_inner<R>(
416 size: Size,
417 align: Align,
418 init: AllocInit,
419 params: <Bytes as AllocBytes>::AllocParams,
420 fail: impl FnOnce() -> R,
421 ) -> Result<Self, R> {
422// We raise an error if we cannot create the allocation on the host.
423 // This results in an error that can happen non-deterministically, since the memory
424 // available to the compiler can change between runs. Normally queries are always
425 // deterministic. However, we can be non-deterministic here because all uses of const
426 // evaluation (including ConstProp!) will make compilation fail (via hard error
427 // or OOM) upon encountering a `MemoryExhausted` error.
428let bytes = Bytes::zeroed(size, align, params).ok_or_else(fail)?;
429430Ok(Allocation {
431bytes,
432 provenance: ProvenanceMap::new(),
433 init_mask: InitMask::new(
434size,
435match init {
436 AllocInit::Uninit => false,
437 AllocInit::Zero => true,
438 },
439 ),
440align,
441 mutability: Mutability::Mut,
442 extra: (),
443 })
444 }
445446/// Try to create an Allocation of `size` bytes, failing if there is not enough memory
447 /// available to the compiler to do so.
448pub fn try_new<'tcx>(
449 size: Size,
450 align: Align,
451 init: AllocInit,
452 params: <Bytes as AllocBytes>::AllocParams,
453 ) -> InterpResult<'tcx, Self> {
454Self::new_inner(size, align, init, params, || {
455 ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
456 InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
457 })
458 .into()
459 }
460461/// Try to create an Allocation of `size` bytes. Aborts if there is not enough memory
462 /// available to the compiler to do so.
463 ///
464 /// Example use case: To obtain an Allocation filled with specific data,
465 /// first call this function and then call write_scalar to fill in the right data.
466pub fn new(
467 size: Size,
468 align: Align,
469 init: AllocInit,
470 params: <Bytes as AllocBytes>::AllocParams,
471 ) -> Self {
472match Self::new_inner(size, align, init, params, || {
473// `size` may actually be bigger than isize::MAX since it is a *target* size.
474 // Clamp it to isize::MAX to still give a somewhat reasonable error message.
475alloc::handle_alloc_error(
476Layout::from_size_align(
477size.bytes().min(isize::MAXas u64) as usize,
478align.bytes_usize(),
479 )
480 .unwrap(),
481 )
482 }) {
483Ok(x) => x,
484Err(x) => x,
485 }
486 }
487488/// Add the extra.
489pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
490Allocation {
491 bytes: self.bytes,
492 provenance: self.provenance,
493 init_mask: self.init_mask,
494 align: self.align,
495 mutability: self.mutability,
496extra,
497 }
498 }
499}
500501impl Allocation {
502/// Adjust allocation from the ones in `tcx` to a custom Machine instance
503 /// with a different `Provenance` and `Byte` type.
504pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>(
505&self,
506 cx: &impl HasDataLayout,
507 alloc_bytes: impl FnOnce(&[u8], Align) -> InterpResult<'tcx, Bytes>,
508mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> InterpResult<'tcx, Pointer<Prov>>,
509 ) -> InterpResult<'tcx, Allocation<Prov, (), Bytes>> {
510// Copy the data.
511let mut bytes = alloc_bytes(&*self.bytes, self.align)?;
512// Adjust provenance of pointers stored in this allocation.
513let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
514let ptr_size = cx.data_layout().pointer_size().bytes_usize();
515let endian = cx.data_layout().endian;
516for &(offset, alloc_id) in self.provenance.ptrs().iter() {
517let idx = offset.bytes_usize();
518let ptr_bytes = &mut bytes[idx..idx + ptr_size];
519let bits = read_target_uint(endian, ptr_bytes).unwrap();
520let (ptr_prov, ptr_offset) =
521 adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts();
522 write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
523 new_provenance.push((offset, ptr_prov));
524 }
525// Create allocation.
526interp_ok(Allocation {
527bytes,
528 provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
529 init_mask: self.init_mask.clone(),
530 align: self.align,
531 mutability: self.mutability,
532 extra: self.extra,
533 })
534 }
535}
536537/// Raw accessors. Provide access to otherwise private bytes.
538impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
539pub fn len(&self) -> usize {
540self.bytes.len()
541 }
542543pub fn size(&self) -> Size {
544Size::from_bytes(self.len())
545 }
546547/// Looks at a slice which may contain uninitialized bytes or provenance. This differs
548 /// from `get_bytes_with_uninit_and_ptr` in that it does no provenance checks (even on the
549 /// edges) at all.
550 /// This must not be used for reads affecting the interpreter execution.
551pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
552&self.bytes[range]
553 }
554555/// Returns the mask indicating which bytes are initialized.
556pub fn init_mask(&self) -> &InitMask {
557&self.init_mask
558 }
559560/// Returns the provenance map.
561pub fn provenance(&self) -> &ProvenanceMap<Prov> {
562&self.provenance
563 }
564}
565566/// Byte accessors.
567impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
568/// This is the entirely abstraction-violating way to just grab the raw bytes without
569 /// caring about provenance or initialization.
570 ///
571 /// This function also guarantees that the resulting pointer will remain stable
572 /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
573 /// on that.
574#[inline]
575pub fn get_bytes_unchecked(&self, range: AllocRange) -> &[u8] {
576&self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
577 }
578579/// Checks that these bytes are initialized, and then strip provenance (if possible) and return
580 /// them.
581 ///
582 /// It is the caller's responsibility to check bounds and alignment beforehand.
583 /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
584 /// on `InterpCx` instead.
585#[inline]
586pub fn get_bytes_strip_provenance(
587&self,
588 cx: &impl HasDataLayout,
589 range: AllocRange,
590 ) -> AllocResult<&[u8]> {
591self.init_mask.is_range_initialized(range).map_err(|uninit_range| {
592 AllocError::InvalidUninitBytes(Some(BadBytesAccess {
593 access: range,
594 bad: uninit_range,
595 }))
596 })?;
597if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) {
598// Find the provenance.
599let (prov_range, _prov) = self600 .provenance
601 .get_range(range, cx)
602 .next()
603 .expect("there must be provenance somewhere here");
604let start = prov_range.start.max(range.start); // the pointer might begin before `range`!
605let end = prov_range.end().min(range.end()); // the pointer might end after `range`!
606return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {
607 access: range,
608 bad: AllocRange::from(start..end),
609 })));
610 }
611Ok(self.get_bytes_unchecked(range))
612 }
613614/// This is the entirely abstraction-violating way to just get mutable access to the raw bytes.
615 /// Just calling this already marks everything as defined and removes provenance, so be sure to
616 /// actually overwrite all the data there!
617 ///
618 /// It is the caller's responsibility to check bounds and alignment beforehand.
619 /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
620 /// on `InterpCx` instead.
621pub fn get_bytes_unchecked_for_overwrite(
622&mut self,
623 cx: &impl HasDataLayout,
624 range: AllocRange,
625 ) -> &mut [u8] {
626self.mark_init(range, true);
627self.provenance.clear(range, &self.bytes, cx);
628629&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
630 }
631632/// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases
633 /// into this memory.
634pub fn get_bytes_unchecked_for_overwrite_ptr(
635&mut self,
636 cx: &impl HasDataLayout,
637 range: AllocRange,
638 ) -> *mut [u8] {
639self.mark_init(range, true);
640self.provenance.clear(range, &self.bytes, cx);
641642if !(range.end().bytes_usize() <= self.bytes.len()) {
::core::panicking::panic("assertion failed: range.end().bytes_usize() <= self.bytes.len()")
};assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
643 // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`.
644let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
645let len = range.end().bytes_usize() - range.start.bytes_usize();
646 ptr::slice_from_raw_parts_mut(begin_ptr, len)
647 }
648649/// This gives direct mutable access to the entire buffer, just exposing their internal state
650 /// without resetting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if
651 /// `OFFSET_IS_ADDR` is true.
652pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 {
653if !Prov::OFFSET_IS_ADDR {
::core::panicking::panic("assertion failed: Prov::OFFSET_IS_ADDR")
};assert!(Prov::OFFSET_IS_ADDR);
654self.bytes.as_mut_ptr()
655 }
656657/// This gives direct immutable access to the entire buffer, just exposing their internal state
658 /// without resetting anything. Directly exposes `AllocBytes::as_ptr`. Only works if
659 /// `OFFSET_IS_ADDR` is true.
660pub fn get_bytes_unchecked_raw(&self) -> *const u8 {
661if !Prov::OFFSET_IS_ADDR {
::core::panicking::panic("assertion failed: Prov::OFFSET_IS_ADDR")
};assert!(Prov::OFFSET_IS_ADDR);
662self.bytes.as_ptr()
663 }
664}
665666/// Reading and writing.
667impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
668/// Sets the init bit for the given range.
669fn mark_init(&mut self, range: AllocRange, is_init: bool) {
670if range.size.bytes() == 0 {
671return;
672 }
673if !(self.mutability == Mutability::Mut) {
::core::panicking::panic("assertion failed: self.mutability == Mutability::Mut")
};assert!(self.mutability == Mutability::Mut);
674self.init_mask.set_range(range, is_init);
675 }
676677/// Reads a *non-ZST* scalar.
678 ///
679 /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine
680 /// supports that) provenance is entirely ignored.
681 ///
682 /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
683 /// for ZSTness anyway due to integer pointers being valid for ZSTs.
684 ///
685 /// It is the caller's responsibility to check bounds and alignment beforehand.
686 /// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
687pub fn read_scalar(
688&self,
689 cx: &impl HasDataLayout,
690 range: AllocRange,
691 read_provenance: bool,
692 ) -> AllocResult<Scalar<Prov>> {
693// First and foremost, if anything is uninit, bail.
694if let Err(bad) = self.init_mask.is_range_initialized(range) {
695return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess {
696 access: range,
697bad,
698 })));
699 }
700701// Get the integer part of the result. We HAVE TO check provenance before returning this!
702let bytes = self.get_bytes_unchecked(range);
703let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
704705if read_provenance {
706{
match (&range.size, &cx.data_layout().pointer_size()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(range.size, cx.data_layout().pointer_size());
707708if let Some(prov) = self.provenance.read_ptr(range.start, cx)? {
709// Assemble the bits with their provenance.
710let ptr = Pointer::new(prov, Size::from_bytes(bits));
711Ok(Scalar::from_pointer(ptr, cx))
712 } else {
713// Return raw bits without provenance.
714Ok(Scalar::from_uint(bits, range.size))
715 }
716 } else {
717// We are *not* reading a pointer.
718 // If we can just ignore provenance or there is none, that's easy.
719if Prov::OFFSET_IS_ADDR || self.provenance.range_empty(range, cx) {
720// We just strip provenance.
721return Ok(Scalar::from_uint(bits, range.size));
722 }
723// There is some provenance and we don't have OFFSET_IS_ADDR. This doesn't work.
724return Err(AllocError::ReadPointerAsInt(None));
725 }
726 }
727728/// Writes a *non-ZST* scalar.
729 ///
730 /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
731 /// for ZSTness anyway due to integer pointers being valid for ZSTs.
732 ///
733 /// It is the caller's responsibility to check bounds and alignment beforehand.
734 /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
735pub fn write_scalar(
736&mut self,
737 cx: &impl HasDataLayout,
738 range: AllocRange,
739 val: Scalar<Prov>,
740 ) -> AllocResult {
741if !(self.mutability == Mutability::Mut) {
::core::panicking::panic("assertion failed: self.mutability == Mutability::Mut")
};assert!(self.mutability == Mutability::Mut);
742743// `to_bits_or_ptr_internal` is the right method because we just want to store this data
744 // as-is into memory. This also double-checks that `val.size()` matches `range.size`.
745let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
746Right(ptr) => {
747let (provenance, offset) = ptr.into_raw_parts();
748 (u128::from(offset.bytes()), Some(provenance))
749 }
750Left(data) => (data, None),
751 };
752753let endian = cx.data_layout().endian;
754// Yes we do overwrite all the bytes in `dst`.
755let dst = self.get_bytes_unchecked_for_overwrite(cx, range);
756write_target_uint(endian, dst, bytes).unwrap();
757758// See if we have to also store some provenance.
759if let Some(provenance) = provenance {
760{
match (&range.size, &cx.data_layout().pointer_size()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(range.size, cx.data_layout().pointer_size());
761self.provenance.insert_ptr(range.start, provenance, cx);
762 }
763764Ok(())
765 }
766767/// Write "uninit" to the given memory range.
768pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
769self.mark_init(range, false);
770self.provenance.clear(range, &self.bytes, cx);
771 }
772773/// Mark all bytes in the given range as initialised and reset the provenance
774 /// to wildcards. This entirely breaks the normal mechanisms for tracking
775 /// initialisation and is only provided for Miri operating in native-lib
776 /// mode. UB will be missed if the underlying bytes were not actually written to.
777 ///
778 /// If `range` is `None`, defaults to performing this on the whole allocation.
779pub fn process_native_write(&mut self, cx: &impl HasDataLayout, range: Option<AllocRange>) {
780let range = range.unwrap_or_else(|| AllocRange {
781 start: Size::ZERO,
782 size: Size::from_bytes(self.len()),
783 });
784self.mark_init(range, true);
785self.provenance.write_wildcards(cx, &self.bytes, range);
786 }
787788/// Remove all provenance in the given memory range.
789pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
790self.provenance.clear(range, &self.bytes, cx);
791 }
792793pub fn provenance_merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
794self.provenance.merge_bytes(cx)
795 }
796797pub fn provenance_prepare_copy(
798&self,
799 range: AllocRange,
800 cx: &impl HasDataLayout,
801 ) -> ProvenanceCopy<Prov> {
802self.provenance.prepare_copy(range, &self.bytes, cx)
803 }
804805/// Applies a previously prepared provenance copy.
806 /// The affected range is expected to be clear of provenance.
807 ///
808 /// This is dangerous to use as it can violate internal `Allocation` invariants!
809 /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
810pub fn provenance_apply_copy(
811&mut self,
812 copy: ProvenanceCopy<Prov>,
813 range: AllocRange,
814 repeat: u64,
815 ) {
816self.provenance.apply_copy(copy, range, repeat)
817 }
818819/// Applies a previously prepared copy of the init mask.
820 ///
821 /// This is dangerous to use as it can violate internal `Allocation` invariants!
822 /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
823pub fn init_mask_apply_copy(&mut self, copy: InitCopy, range: AllocRange, repeat: u64) {
824self.init_mask.apply_copy(copy, range, repeat)
825 }
826}