Skip to main content

rustc_middle/mir/interpret/
allocation.rs

1//! The virtual memory representation of the MIR interpreter.
2
3mod init_mask;
4mod provenance_map;
5
6use std::alloc::{self, Layout};
7use std::borrow::Cow;
8use std::hash::Hash;
9use std::ops::{Deref, DerefMut, Range};
10use std::{fmt, hash, ptr};
11
12use 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};
21
22use super::{
23    AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer, Provenance,
24    ResourceExhaustionInfo, Scalar, UndefinedBehaviorInfo, UnsupportedOpInfo, interp_ok,
25    read_target_uint, write_target_uint,
26};
27use crate::ty;
28
29/// 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.
34    type AllocParams;
35
36    /// Create an `AllocBytes` from a slice of `u8`.
37    fn from_bytes<'a>(
38        slice: impl Into<Cow<'a, [u8]>>,
39        _align: Align,
40        _params: Self::AllocParams,
41    ) -> Self;
42
43    /// Create a zeroed `AllocBytes` of the specified size and alignment.
44    /// Returns `None` if we ran out of memory on the host.
45    fn zeroed(size: Size, _align: Align, _params: Self::AllocParams) -> Option<Self>;
46
47    /// 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.
52    fn as_mut_ptr(&mut self) -> *mut u8;
53
54    /// 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.
59    fn as_ptr(&self) -> *const u8;
60}
61
62/// Default `bytes` for `Allocation` is a `Box<u8>`.
63impl AllocBytes for Box<[u8]> {
64    type AllocParams = ();
65
66    fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align, _params: ()) -> Self {
67        Box::<[u8]>::from(slice.into())
68    }
69
70    fn zeroed(size: Size, _align: Align, _params: ()) -> Option<Self> {
71        let 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]>
73        let bytes = unsafe { bytes.assume_init() };
74        Some(bytes)
75    }
76
77    fn as_mut_ptr(&mut self) -> *mut u8 {
78        Box::as_mut_ptr(self).cast()
79    }
80
81    fn as_ptr(&self) -> *const u8 {
82        Box::as_ptr(self).cast()
83    }
84}
85
86/// 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.
98    bytes: 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.
103    provenance: ProvenanceMap<Prov>,
104    /// Denotes which part of this allocation is initialized.
105    ///
106    /// Invariant: the uninitialized parts have no provenance.
107    init_mask: InitMask,
108    /// The alignment of the allocation to detect unaligned reads.
109    /// (`Align` guarantees that this is a power of two.)
110    pub 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.
114    pub mutability: Mutability,
115    /// Extra state for the machine.
116    pub extra: Extra,
117}
118
119/// 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}
127
128impl<E: Encoder> Encodable<E> for AllocFlags {
129    fn encode(&self, encoder: &mut E) {
130        // Make sure Align::MAX can be stored with the high 2 bits unset.
131        const {
132            let max_supported_align_repr = u8::MAX >> 2;
133            let max_supported_align = 1 << max_supported_align_repr;
134            if !(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        }
136
137        let mut flags = self.align.bytes().trailing_zeros() as u8;
138        flags |= match self.mutability {
139            Mutability::Not => 0,
140            Mutability::Mut => 1 << 6,
141        };
142        flags |= (self.all_zero as u8) << 7;
143        flags.encode(encoder);
144    }
145}
146
147impl<D: Decoder> Decodable<D> for AllocFlags {
148    fn decode(decoder: &mut D) -> Self {
149        let flags: u8 = Decodable::decode(decoder);
150        let align = flags & 0b0011_1111;
151        let mutability = flags & 0b0100_0000;
152        let all_zero = flags & 0b1000_0000;
153
154        let align = Align::from_bytes(1 << align).unwrap();
155        let mutability = match mutability {
156            0 => Mutability::Not,
157            _ => Mutability::Mut,
158        };
159        let all_zero = all_zero > 0;
160
161        AllocFlags { align, mutability, all_zero }
162    }
163}
164
165/// 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.
174    if buf.is_empty() {
175        return true;
176    }
177    // Just fast-rejecting based on the first element significantly reduces the amount that we end
178    // up walking the whole array.
179    if buf[0] != 0 {
180        return false;
181    }
182
183    // 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.
185    buf.iter().fold(true, |acc, b| acc & (*b == 0))
186}
187
188/// 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
191    ProvenanceMap<Prov>: Encodable<E>,
192    Extra: Encodable<E>,
193{
194    fn encode(&self, encoder: &mut E) {
195        let all_zero = all_zero(&self.bytes);
196        AllocFlags { align: self.align, mutability: self.mutability, all_zero }.encode(encoder);
197
198        encoder.emit_usize(self.bytes.len());
199        if !all_zero {
200            encoder.emit_raw_bytes(&self.bytes);
201        }
202        self.provenance.encode(encoder);
203        self.init_mask.encode(encoder);
204        self.extra.encode(encoder);
205    }
206}
207
208impl<Prov: Provenance, Extra, D: Decoder> Decodable<D> for Allocation<Prov, Extra, Box<[u8]>>
209where
210    ProvenanceMap<Prov>: Decodable<D>,
211    Extra: Decodable<D>,
212{
213    fn decode(decoder: &mut D) -> Self {
214        let AllocFlags { align, mutability, all_zero } = Decodable::decode(decoder);
215
216        let len = decoder.read_usize();
217        let bytes = if all_zero { ::alloc::vec::from_elem(0u8, len)vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() };
218        let bytes = <Box<[u8]> as AllocBytes>::from_bytes(bytes, align, ());
219
220        let provenance = Decodable::decode(decoder);
221        let init_mask = Decodable::decode(decoder);
222        let extra = Decodable::decode(decoder);
223
224        Self { bytes, provenance, init_mask, align, mutability, extra }
225    }
226}
227
228/// 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;
233
234/// 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;
238
239// 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::Hash for Allocation {
244    fn hash<H: hash::Hasher>(&self, state: &mut H) {
245        let Self {
246            bytes,
247            provenance,
248            init_mask,
249            align,
250            mutability,
251            extra: (), // don't bother hashing ()
252        } = self;
253
254        // 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.
256        let byte_count = bytes.len();
257        if byte_count > MAX_HASHED_BUFFER_LEN {
258            // Hash the buffer's length.
259            byte_count.hash(state);
260
261            // And its head and tail.
262            bytes[..MAX_BYTES_TO_HASH].hash(state);
263            bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state);
264        } else {
265            bytes.hash(state);
266        }
267
268        // Hash the other fields as usual.
269        provenance.hash(state);
270        init_mask.hash(state);
271        align.hash(state);
272        mutability.hash(state);
273    }
274}
275
276/// 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>);
287
288impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
289    fn 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.
292        f.write_fmt(format_args!("ConstAllocation {{ .. }}"))write!(f, "ConstAllocation {{ .. }}")
293    }
294}
295
296impl<'tcx> ConstAllocation<'tcx> {
297    pub fn inner(self) -> &'tcx Allocation {
298        self.0.0
299    }
300}
301
302/// 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.
307    ReadPointerAsInt(Option<BadBytesAccess>),
308    /// Partially copying a pointer.
309    ReadPartialPointer(Size),
310    /// Using uninitialized data where it is not allowed.
311    InvalidUninitBytes(Option<BadBytesAccess>),
312}
313pub type AllocResult<T = ()> = Result<T, AllocError>;
314
315impl AllocError {
316    pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpErrorKind<'tcx> {
317        use AllocError::*;
318        match self {
319            ReadPointerAsInt(info) => InterpErrorKind::Unsupported(
320                UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))),
321            ),
322            ReadPartialPointer(offset) => InterpErrorKind::Unsupported(
323                UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)),
324            ),
325            InvalidUninitBytes(info) => InterpErrorKind::UndefinedBehavior(
326                UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
327            ),
328        }
329    }
330}
331
332/// 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 {
335    pub start: Size,
336    pub size: Size,
337}
338
339impl fmt::Display for AllocRange {
340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341        f.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}
344
345/// Free-starting constructor for less syntactic overhead.
346#[inline(always)]
347pub fn alloc_range(start: Size, size: Size) -> AllocRange {
348    AllocRange { start, size }
349}
350
351impl From<Range<Size>> for AllocRange {
352    #[inline]
353    fn from(r: Range<Size>) -> Self {
354        alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
355    }
356}
357
358impl From<Range<usize>> for AllocRange {
359    #[inline]
360    fn from(r: Range<usize>) -> Self {
361        AllocRange::from(Size::from_bytes(r.start)..Size::from_bytes(r.end))
362    }
363}
364
365impl AllocRange {
366    #[inline(always)]
367    pub fn end(self) -> Size {
368        self.start + self.size // This does overflow checking.
369    }
370
371    /// Returns the `subrange` within this range; panics if it is not a subrange.
372    #[inline]
373    pub fn subrange(self, subrange: AllocRange) -> AllocRange {
374        let sub_start = self.start + subrange.start;
375        let range = alloc_range(sub_start, subrange.size);
376        if !(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");
377        range
378    }
379}
380
381/// Whether a new allocation should be initialized with zero-bytes.
382pub enum AllocInit {
383    Uninit,
384    Zero,
385}
386
387// 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
390    pub 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 {
396        let bytes = Bytes::from_bytes(slice, align, params);
397        let size = Size::from_bytes(bytes.len());
398        Self {
399            bytes,
400            provenance: ProvenanceMap::new(),
401            init_mask: InitMask::new(size, true),
402            align,
403            mutability,
404            extra: (),
405        }
406    }
407
408    pub fn from_bytes_byte_aligned_immutable<'a>(
409        slice: impl Into<Cow<'a, [u8]>>,
410        params: <Bytes as AllocBytes>::AllocParams,
411    ) -> Self {
412        Allocation::from_bytes(slice, Align::ONE, Mutability::Not, params)
413    }
414
415    fn 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.
428        let bytes = Bytes::zeroed(size, align, params).ok_or_else(fail)?;
429
430        Ok(Allocation {
431            bytes,
432            provenance: ProvenanceMap::new(),
433            init_mask: InitMask::new(
434                size,
435                match init {
436                    AllocInit::Uninit => false,
437                    AllocInit::Zero => true,
438                },
439            ),
440            align,
441            mutability: Mutability::Mut,
442            extra: (),
443        })
444    }
445
446    /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
447    /// available to the compiler to do so.
448    pub fn try_new<'tcx>(
449        size: Size,
450        align: Align,
451        init: AllocInit,
452        params: <Bytes as AllocBytes>::AllocParams,
453    ) -> InterpResult<'tcx, Self> {
454        Self::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    }
460
461    /// 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.
466    pub fn new(
467        size: Size,
468        align: Align,
469        init: AllocInit,
470        params: <Bytes as AllocBytes>::AllocParams,
471    ) -> Self {
472        match 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.
475            alloc::handle_alloc_error(
476                Layout::from_size_align(
477                    size.bytes().min(isize::MAX as u64) as usize,
478                    align.bytes_usize(),
479                )
480                .unwrap(),
481            )
482        }) {
483            Ok(x) => x,
484            Err(x) => x,
485        }
486    }
487
488    /// Add the extra.
489    pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
490        Allocation {
491            bytes: self.bytes,
492            provenance: self.provenance,
493            init_mask: self.init_mask,
494            align: self.align,
495            mutability: self.mutability,
496            extra,
497        }
498    }
499}
500
501impl Allocation {
502    /// Adjust allocation from the ones in `tcx` to a custom Machine instance
503    /// with a different `Provenance` and `Byte` type.
504    pub 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>,
508        mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> InterpResult<'tcx, Pointer<Prov>>,
509    ) -> InterpResult<'tcx, Allocation<Prov, (), Bytes>> {
510        // Copy the data.
511        let mut bytes = alloc_bytes(&*self.bytes, self.align)?;
512        // Adjust provenance of pointers stored in this allocation.
513        let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
514        let ptr_size = cx.data_layout().pointer_size().bytes_usize();
515        let endian = cx.data_layout().endian;
516        for &(offset, alloc_id) in self.provenance.ptrs().iter() {
517            let idx = offset.bytes_usize();
518            let ptr_bytes = &mut bytes[idx..idx + ptr_size];
519            let bits = read_target_uint(endian, ptr_bytes).unwrap();
520            let (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.
526        interp_ok(Allocation {
527            bytes,
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}
536
537/// Raw accessors. Provide access to otherwise private bytes.
538impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
539    pub fn len(&self) -> usize {
540        self.bytes.len()
541    }
542
543    pub fn size(&self) -> Size {
544        Size::from_bytes(self.len())
545    }
546
547    /// 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.
551    pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
552        &self.bytes[range]
553    }
554
555    /// Returns the mask indicating which bytes are initialized.
556    pub fn init_mask(&self) -> &InitMask {
557        &self.init_mask
558    }
559
560    /// Returns the provenance map.
561    pub fn provenance(&self) -> &ProvenanceMap<Prov> {
562        &self.provenance
563    }
564}
565
566/// 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]
575    pub fn get_bytes_unchecked(&self, range: AllocRange) -> &[u8] {
576        &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
577    }
578
579    /// 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]
586    pub fn get_bytes_strip_provenance(
587        &self,
588        cx: &impl HasDataLayout,
589        range: AllocRange,
590    ) -> AllocResult<&[u8]> {
591        self.init_mask.is_range_initialized(range).map_err(|uninit_range| {
592            AllocError::InvalidUninitBytes(Some(BadBytesAccess {
593                access: range,
594                bad: uninit_range,
595            }))
596        })?;
597        if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) {
598            // Find the provenance.
599            let (prov_range, _prov) = self
600                .provenance
601                .get_range(range, cx)
602                .next()
603                .expect("there must be provenance somewhere here");
604            let start = prov_range.start.max(range.start); // the pointer might begin before `range`!
605            let end = prov_range.end().min(range.end()); // the pointer might end after `range`!
606            return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {
607                access: range,
608                bad: AllocRange::from(start..end),
609            })));
610        }
611        Ok(self.get_bytes_unchecked(range))
612    }
613
614    /// 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.
621    pub fn get_bytes_unchecked_for_overwrite(
622        &mut self,
623        cx: &impl HasDataLayout,
624        range: AllocRange,
625    ) -> &mut [u8] {
626        self.mark_init(range, true);
627        self.provenance.clear(range, &self.bytes, cx);
628
629        &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
630    }
631
632    /// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases
633    /// into this memory.
634    pub fn get_bytes_unchecked_for_overwrite_ptr(
635        &mut self,
636        cx: &impl HasDataLayout,
637        range: AllocRange,
638    ) -> *mut [u8] {
639        self.mark_init(range, true);
640        self.provenance.clear(range, &self.bytes, cx);
641
642        if !(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`.
644        let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
645        let len = range.end().bytes_usize() - range.start.bytes_usize();
646        ptr::slice_from_raw_parts_mut(begin_ptr, len)
647    }
648
649    /// 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.
652    pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 {
653        if !Prov::OFFSET_IS_ADDR {
    ::core::panicking::panic("assertion failed: Prov::OFFSET_IS_ADDR")
};assert!(Prov::OFFSET_IS_ADDR);
654        self.bytes.as_mut_ptr()
655    }
656
657    /// 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.
660    pub fn get_bytes_unchecked_raw(&self) -> *const u8 {
661        if !Prov::OFFSET_IS_ADDR {
    ::core::panicking::panic("assertion failed: Prov::OFFSET_IS_ADDR")
};assert!(Prov::OFFSET_IS_ADDR);
662        self.bytes.as_ptr()
663    }
664}
665
666/// Reading and writing.
667impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
668    /// Sets the init bit for the given range.
669    fn mark_init(&mut self, range: AllocRange, is_init: bool) {
670        if range.size.bytes() == 0 {
671            return;
672        }
673        if !(self.mutability == Mutability::Mut) {
    ::core::panicking::panic("assertion failed: self.mutability == Mutability::Mut")
};assert!(self.mutability == Mutability::Mut);
674        self.init_mask.set_range(range, is_init);
675    }
676
677    /// 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.
687    pub 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.
694        if let Err(bad) = self.init_mask.is_range_initialized(range) {
695            return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess {
696                access: range,
697                bad,
698            })));
699        }
700
701        // Get the integer part of the result. We HAVE TO check provenance before returning this!
702        let bytes = self.get_bytes_unchecked(range);
703        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
704
705        if 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());
707
708            if let Some(prov) = self.provenance.read_ptr(range.start, cx)? {
709                // Assemble the bits with their provenance.
710                let ptr = Pointer::new(prov, Size::from_bytes(bits));
711                Ok(Scalar::from_pointer(ptr, cx))
712            } else {
713                // Return raw bits without provenance.
714                Ok(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.
719            if Prov::OFFSET_IS_ADDR || self.provenance.range_empty(range, cx) {
720                // We just strip provenance.
721                return 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.
724            return Err(AllocError::ReadPointerAsInt(None));
725        }
726    }
727
728    /// 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.
735    pub fn write_scalar(
736        &mut self,
737        cx: &impl HasDataLayout,
738        range: AllocRange,
739        val: Scalar<Prov>,
740    ) -> AllocResult {
741        if !(self.mutability == Mutability::Mut) {
    ::core::panicking::panic("assertion failed: self.mutability == Mutability::Mut")
};assert!(self.mutability == Mutability::Mut);
742
743        // `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`.
745        let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
746            Right(ptr) => {
747                let (provenance, offset) = ptr.into_raw_parts();
748                (u128::from(offset.bytes()), Some(provenance))
749            }
750            Left(data) => (data, None),
751        };
752
753        let endian = cx.data_layout().endian;
754        // Yes we do overwrite all the bytes in `dst`.
755        let dst = self.get_bytes_unchecked_for_overwrite(cx, range);
756        write_target_uint(endian, dst, bytes).unwrap();
757
758        // See if we have to also store some provenance.
759        if 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());
761            self.provenance.insert_ptr(range.start, provenance, cx);
762        }
763
764        Ok(())
765    }
766
767    /// Write "uninit" to the given memory range.
768    pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
769        self.mark_init(range, false);
770        self.provenance.clear(range, &self.bytes, cx);
771    }
772
773    /// 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.
779    pub fn process_native_write(&mut self, cx: &impl HasDataLayout, range: Option<AllocRange>) {
780        let range = range.unwrap_or_else(|| AllocRange {
781            start: Size::ZERO,
782            size: Size::from_bytes(self.len()),
783        });
784        self.mark_init(range, true);
785        self.provenance.write_wildcards(cx, &self.bytes, range);
786    }
787
788    /// Remove all provenance in the given memory range.
789    pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
790        self.provenance.clear(range, &self.bytes, cx);
791    }
792
793    pub fn provenance_merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
794        self.provenance.merge_bytes(cx)
795    }
796
797    pub fn provenance_prepare_copy(
798        &self,
799        range: AllocRange,
800        cx: &impl HasDataLayout,
801    ) -> ProvenanceCopy<Prov> {
802        self.provenance.prepare_copy(range, &self.bytes, cx)
803    }
804
805    /// 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`.
810    pub fn provenance_apply_copy(
811        &mut self,
812        copy: ProvenanceCopy<Prov>,
813        range: AllocRange,
814        repeat: u64,
815    ) {
816        self.provenance.apply_copy(copy, range, repeat)
817    }
818
819    /// 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`.
823    pub fn init_mask_apply_copy(&mut self, copy: InitCopy, range: AllocRange, repeat: u64) {
824        self.init_mask.apply_copy(copy, range, repeat)
825    }
826}