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::borrow::Cow;
7use std::hash::Hash;
8use std::ops::{Deref, DerefMut, Range};
9use std::{fmt, hash, ptr};
10
11use either::{Left, Right};
12use init_mask::*;
13pub use init_mask::{InitChunk, InitChunkIter};
14use provenance_map::*;
15use rustc_abi::{Align, HasDataLayout, Size};
16use rustc_ast::Mutability;
17use rustc_data_structures::intern::Interned;
18use rustc_macros::HashStable;
19use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
20
21use super::{
22    AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer,
23    PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
24    UndefinedBehaviorInfo, UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint,
25};
26use crate::ty;
27
28/// Functionality required for the bytes of an `Allocation`.
29pub trait AllocBytes: Clone + fmt::Debug + Deref<Target = [u8]> + DerefMut<Target = [u8]> {
30    /// The type of extra parameters passed in when creating an allocation.
31    /// Can be used by `interpret::Machine` instances to make runtime-configuration-dependent
32    /// decisions about the allocation strategy.
33    type AllocParams;
34
35    /// Create an `AllocBytes` from a slice of `u8`.
36    fn from_bytes<'a>(
37        slice: impl Into<Cow<'a, [u8]>>,
38        _align: Align,
39        _params: Self::AllocParams,
40    ) -> Self;
41
42    /// Create a zeroed `AllocBytes` of the specified size and alignment.
43    /// Returns `None` if we ran out of memory on the host.
44    fn zeroed(size: Size, _align: Align, _params: Self::AllocParams) -> Option<Self>;
45
46    /// Gives direct access to the raw underlying storage.
47    ///
48    /// Crucially this pointer is compatible with:
49    /// - other pointers returned by this method, and
50    /// - references returned from `deref()`, as long as there was no write.
51    fn as_mut_ptr(&mut self) -> *mut u8;
52
53    /// Gives direct access to the raw underlying storage.
54    ///
55    /// Crucially this pointer is compatible with:
56    /// - other pointers returned by this method, and
57    /// - references returned from `deref()`, as long as there was no write.
58    fn as_ptr(&self) -> *const u8;
59}
60
61/// Default `bytes` for `Allocation` is a `Box<u8>`.
62impl AllocBytes for Box<[u8]> {
63    type AllocParams = ();
64
65    fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align, _params: ()) -> Self {
66        Box::<[u8]>::from(slice.into())
67    }
68
69    fn zeroed(size: Size, _align: Align, _params: ()) -> Option<Self> {
70        let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?;
71        // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
72        let bytes = unsafe { bytes.assume_init() };
73        Some(bytes)
74    }
75
76    fn as_mut_ptr(&mut self) -> *mut u8 {
77        Box::as_mut_ptr(self).cast()
78    }
79
80    fn as_ptr(&self) -> *const u8 {
81        Box::as_ptr(self).cast()
82    }
83}
84
85/// This type represents an Allocation in the Miri/CTFE core engine.
86///
87/// Its public API is rather low-level, working directly with allocation offsets and a custom error
88/// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory`
89/// module provides higher-level access.
90// Note: for performance reasons when interning, some of the `Allocation` fields can be partially
91// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
92#[derive(Clone, Eq, PartialEq)]
93#[derive(HashStable)]
94pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> {
95    /// The actual bytes of the allocation.
96    /// Note that the bytes of a pointer represent the offset of the pointer.
97    bytes: Bytes,
98    /// Maps from byte addresses to extra provenance data for each pointer.
99    /// Only the first byte of a pointer is inserted into the map; i.e.,
100    /// every entry in this map applies to `pointer_size` consecutive bytes starting
101    /// at the given offset.
102    provenance: ProvenanceMap<Prov>,
103    /// Denotes which part of this allocation is initialized.
104    ///
105    /// Invariant: the uninitialized parts have no provenance.
106    init_mask: InitMask,
107    /// The alignment of the allocation to detect unaligned reads.
108    /// (`Align` guarantees that this is a power of two.)
109    pub align: Align,
110    /// `true` if the allocation is mutable.
111    /// Also used by codegen to determine if a static should be put into mutable memory,
112    /// which happens for `static mut` and `static` with interior mutability.
113    pub mutability: Mutability,
114    /// Extra state for the machine.
115    pub extra: Extra,
116}
117
118/// Helper struct that packs an alignment, mutability, and "all bytes are zero" flag together.
119///
120/// Alignment values always have 2 free high bits, and we check for this in our [`Encodable`] impl.
121struct AllocFlags {
122    align: Align,
123    mutability: Mutability,
124    all_zero: bool,
125}
126
127impl<E: Encoder> Encodable<E> for AllocFlags {
128    fn encode(&self, encoder: &mut E) {
129        // Make sure Align::MAX can be stored with the high 2 bits unset.
130        const {
131            let max_supported_align_repr = u8::MAX >> 2;
132            let max_supported_align = 1 << max_supported_align_repr;
133            assert!(Align::MAX.bytes() <= max_supported_align)
134        }
135
136        let mut flags = self.align.bytes().trailing_zeros() as u8;
137        flags |= match self.mutability {
138            Mutability::Not => 0,
139            Mutability::Mut => 1 << 6,
140        };
141        flags |= (self.all_zero as u8) << 7;
142        flags.encode(encoder);
143    }
144}
145
146impl<D: Decoder> Decodable<D> for AllocFlags {
147    fn decode(decoder: &mut D) -> Self {
148        let flags: u8 = Decodable::decode(decoder);
149        let align = flags & 0b0011_1111;
150        let mutability = flags & 0b0100_0000;
151        let all_zero = flags & 0b1000_0000;
152
153        let align = Align::from_bytes(1 << align).unwrap();
154        let mutability = match mutability {
155            0 => Mutability::Not,
156            _ => Mutability::Mut,
157        };
158        let all_zero = all_zero > 0;
159
160        AllocFlags { align, mutability, all_zero }
161    }
162}
163
164/// Efficiently detect whether a slice of `u8` is all zero.
165///
166/// This is used in encoding of [`Allocation`] to special-case all-zero allocations. It is only
167/// optimized a little, because for many allocations the encoding of the actual bytes does not
168/// dominate runtime.
169#[inline]
170fn all_zero(buf: &[u8]) -> bool {
171    // In the empty case we wouldn't encode any contents even without this system where we
172    // special-case allocations whose contents are all 0. We can return anything in the empty case.
173    if buf.is_empty() {
174        return true;
175    }
176    // Just fast-rejecting based on the first element significantly reduces the amount that we end
177    // up walking the whole array.
178    if buf[0] != 0 {
179        return false;
180    }
181
182    // This strategy of combining all slice elements with & or | is unbeatable for the large
183    // all-zero case because it is so well-understood by autovectorization.
184    buf.iter().fold(true, |acc, b| acc & (*b == 0))
185}
186
187/// Custom encoder for [`Allocation`] to more efficiently represent the case where all bytes are 0.
188impl<Prov: Provenance, Extra, E: Encoder> Encodable<E> for Allocation<Prov, Extra, Box<[u8]>>
189where
190    ProvenanceMap<Prov>: Encodable<E>,
191    Extra: Encodable<E>,
192{
193    fn encode(&self, encoder: &mut E) {
194        let all_zero = all_zero(&self.bytes);
195        AllocFlags { align: self.align, mutability: self.mutability, all_zero }.encode(encoder);
196
197        encoder.emit_usize(self.bytes.len());
198        if !all_zero {
199            encoder.emit_raw_bytes(&self.bytes);
200        }
201        self.provenance.encode(encoder);
202        self.init_mask.encode(encoder);
203        self.extra.encode(encoder);
204    }
205}
206
207impl<Prov: Provenance, Extra, D: Decoder> Decodable<D> for Allocation<Prov, Extra, Box<[u8]>>
208where
209    ProvenanceMap<Prov>: Decodable<D>,
210    Extra: Decodable<D>,
211{
212    fn decode(decoder: &mut D) -> Self {
213        let AllocFlags { align, mutability, all_zero } = Decodable::decode(decoder);
214
215        let len = decoder.read_usize();
216        let bytes = if all_zero { vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() };
217        let bytes = <Box<[u8]> as AllocBytes>::from_bytes(bytes, align, ());
218
219        let provenance = Decodable::decode(decoder);
220        let init_mask = Decodable::decode(decoder);
221        let extra = Decodable::decode(decoder);
222
223        Self { bytes, provenance, init_mask, align, mutability, extra }
224    }
225}
226
227/// This is the maximum size we will hash at a time, when interning an `Allocation` and its
228/// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer.
229/// Used when these two structures are large: we only partially hash the larger fields in that
230/// situation. See the comment at the top of their respective `Hash` impl for more details.
231const MAX_BYTES_TO_HASH: usize = 64;
232
233/// This is the maximum size (in bytes) for which a buffer will be fully hashed, when interning.
234/// Otherwise, it will be partially hashed in 2 slices, requiring at least 2 `MAX_BYTES_TO_HASH`
235/// bytes.
236const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH;
237
238// Const allocations are only hashed for interning. However, they can be large, making the hashing
239// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
240// big buffers like the actual bytes of allocation. We can partially hash some fields when they're
241// large.
242impl hash::Hash for Allocation {
243    fn hash<H: hash::Hasher>(&self, state: &mut H) {
244        let Self {
245            bytes,
246            provenance,
247            init_mask,
248            align,
249            mutability,
250            extra: (), // don't bother hashing ()
251        } = self;
252
253        // Partially hash the `bytes` buffer when it is large. To limit collisions with common
254        // prefixes and suffixes, we hash the length and some slices of the buffer.
255        let byte_count = bytes.len();
256        if byte_count > MAX_HASHED_BUFFER_LEN {
257            // Hash the buffer's length.
258            byte_count.hash(state);
259
260            // And its head and tail.
261            bytes[..MAX_BYTES_TO_HASH].hash(state);
262            bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state);
263        } else {
264            bytes.hash(state);
265        }
266
267        // Hash the other fields as usual.
268        provenance.hash(state);
269        init_mask.hash(state);
270        align.hash(state);
271        mutability.hash(state);
272    }
273}
274
275/// Interned types generally have an `Outer` type and an `Inner` type, where
276/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
277/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
278/// outer type and `TyKind` is its inner type.
279///
280/// Here things are different because only const allocations are interned. This
281/// means that both the inner type (`Allocation`) and the outer type
282/// (`ConstAllocation`) are used quite a bit.
283#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
284#[rustc_pass_by_value]
285pub struct ConstAllocation<'tcx>(pub Interned<'tcx, Allocation>);
286
287impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289        // The debug representation of this is very verbose and basically useless,
290        // so don't print it.
291        write!(f, "ConstAllocation {{ .. }}")
292    }
293}
294
295impl<'tcx> ConstAllocation<'tcx> {
296    pub fn inner(self) -> &'tcx Allocation {
297        self.0.0
298    }
299}
300
301/// We have our own error type that does not know about the `AllocId`; that information
302/// is added when converting to `InterpError`.
303#[derive(Debug)]
304pub enum AllocError {
305    /// A scalar had the wrong size.
306    ScalarSizeMismatch(ScalarSizeMismatch),
307    /// Encountered a pointer where we needed raw bytes.
308    ReadPointerAsInt(Option<BadBytesAccess>),
309    /// Partially overwriting a pointer.
310    OverwritePartialPointer(Size),
311    /// Partially copying a pointer.
312    ReadPartialPointer(Size),
313    /// Using uninitialized data where it is not allowed.
314    InvalidUninitBytes(Option<BadBytesAccess>),
315}
316pub type AllocResult<T = ()> = Result<T, AllocError>;
317
318impl From<ScalarSizeMismatch> for AllocError {
319    fn from(s: ScalarSizeMismatch) -> Self {
320        AllocError::ScalarSizeMismatch(s)
321    }
322}
323
324impl AllocError {
325    pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpErrorKind<'tcx> {
326        use AllocError::*;
327        match self {
328            ScalarSizeMismatch(s) => {
329                InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
330            }
331            ReadPointerAsInt(info) => InterpErrorKind::Unsupported(
332                UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))),
333            ),
334            OverwritePartialPointer(offset) => InterpErrorKind::Unsupported(
335                UnsupportedOpInfo::OverwritePartialPointer(Pointer::new(alloc_id, offset)),
336            ),
337            ReadPartialPointer(offset) => InterpErrorKind::Unsupported(
338                UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)),
339            ),
340            InvalidUninitBytes(info) => InterpErrorKind::UndefinedBehavior(
341                UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
342            ),
343        }
344    }
345}
346
347/// The information that makes up a memory access: offset and size.
348#[derive(Copy, Clone)]
349pub struct AllocRange {
350    pub start: Size,
351    pub size: Size,
352}
353
354impl fmt::Debug for AllocRange {
355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356        write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes())
357    }
358}
359
360/// Free-starting constructor for less syntactic overhead.
361#[inline(always)]
362pub fn alloc_range(start: Size, size: Size) -> AllocRange {
363    AllocRange { start, size }
364}
365
366impl From<Range<Size>> for AllocRange {
367    #[inline]
368    fn from(r: Range<Size>) -> Self {
369        alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
370    }
371}
372
373impl From<Range<usize>> for AllocRange {
374    #[inline]
375    fn from(r: Range<usize>) -> Self {
376        AllocRange::from(Size::from_bytes(r.start)..Size::from_bytes(r.end))
377    }
378}
379
380impl AllocRange {
381    #[inline(always)]
382    pub fn end(self) -> Size {
383        self.start + self.size // This does overflow checking.
384    }
385
386    /// Returns the `subrange` within this range; panics if it is not a subrange.
387    #[inline]
388    pub fn subrange(self, subrange: AllocRange) -> AllocRange {
389        let sub_start = self.start + subrange.start;
390        let range = alloc_range(sub_start, subrange.size);
391        assert!(range.end() <= self.end(), "access outside the bounds for given AllocRange");
392        range
393    }
394}
395
396/// Whether a new allocation should be initialized with zero-bytes.
397pub enum AllocInit {
398    Uninit,
399    Zero,
400}
401
402// The constructors are all without extra; the extra gets added by a machine hook later.
403impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
404    /// Creates an allocation initialized by the given bytes
405    pub fn from_bytes<'a>(
406        slice: impl Into<Cow<'a, [u8]>>,
407        align: Align,
408        mutability: Mutability,
409        params: <Bytes as AllocBytes>::AllocParams,
410    ) -> Self {
411        let bytes = Bytes::from_bytes(slice, align, params);
412        let size = Size::from_bytes(bytes.len());
413        Self {
414            bytes,
415            provenance: ProvenanceMap::new(),
416            init_mask: InitMask::new(size, true),
417            align,
418            mutability,
419            extra: (),
420        }
421    }
422
423    pub fn from_bytes_byte_aligned_immutable<'a>(
424        slice: impl Into<Cow<'a, [u8]>>,
425        params: <Bytes as AllocBytes>::AllocParams,
426    ) -> Self {
427        Allocation::from_bytes(slice, Align::ONE, Mutability::Not, params)
428    }
429
430    fn new_inner<R>(
431        size: Size,
432        align: Align,
433        init: AllocInit,
434        params: <Bytes as AllocBytes>::AllocParams,
435        fail: impl FnOnce() -> R,
436    ) -> Result<Self, R> {
437        // We raise an error if we cannot create the allocation on the host.
438        // This results in an error that can happen non-deterministically, since the memory
439        // available to the compiler can change between runs. Normally queries are always
440        // deterministic. However, we can be non-deterministic here because all uses of const
441        // evaluation (including ConstProp!) will make compilation fail (via hard error
442        // or ICE) upon encountering a `MemoryExhausted` error.
443        let bytes = Bytes::zeroed(size, align, params).ok_or_else(fail)?;
444
445        Ok(Allocation {
446            bytes,
447            provenance: ProvenanceMap::new(),
448            init_mask: InitMask::new(
449                size,
450                match init {
451                    AllocInit::Uninit => false,
452                    AllocInit::Zero => true,
453                },
454            ),
455            align,
456            mutability: Mutability::Mut,
457            extra: (),
458        })
459    }
460
461    /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
462    /// available to the compiler to do so.
463    pub fn try_new<'tcx>(
464        size: Size,
465        align: Align,
466        init: AllocInit,
467        params: <Bytes as AllocBytes>::AllocParams,
468    ) -> InterpResult<'tcx, Self> {
469        Self::new_inner(size, align, init, params, || {
470            ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
471            InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
472        })
473        .into()
474    }
475
476    /// Try to create an Allocation of `size` bytes, panics if there is not enough memory
477    /// available to the compiler to do so.
478    ///
479    /// Example use case: To obtain an Allocation filled with specific data,
480    /// first call this function and then call write_scalar to fill in the right data.
481    pub fn new(
482        size: Size,
483        align: Align,
484        init: AllocInit,
485        params: <Bytes as AllocBytes>::AllocParams,
486    ) -> Self {
487        match Self::new_inner(size, align, init, params, || {
488            panic!(
489                "interpreter ran out of memory: cannot create allocation of {} bytes",
490                size.bytes()
491            );
492        }) {
493            Ok(x) => x,
494            Err(x) => x,
495        }
496    }
497
498    /// Add the extra.
499    pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
500        Allocation {
501            bytes: self.bytes,
502            provenance: self.provenance,
503            init_mask: self.init_mask,
504            align: self.align,
505            mutability: self.mutability,
506            extra,
507        }
508    }
509}
510
511impl Allocation {
512    /// Adjust allocation from the ones in `tcx` to a custom Machine instance
513    /// with a different `Provenance` and `Byte` type.
514    pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>(
515        &self,
516        cx: &impl HasDataLayout,
517        alloc_bytes: impl FnOnce(&[u8], Align) -> InterpResult<'tcx, Bytes>,
518        mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> InterpResult<'tcx, Pointer<Prov>>,
519    ) -> InterpResult<'tcx, Allocation<Prov, (), Bytes>> {
520        // Copy the data.
521        let mut bytes = alloc_bytes(&*self.bytes, self.align)?;
522        // Adjust provenance of pointers stored in this allocation.
523        let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
524        let ptr_size = cx.data_layout().pointer_size().bytes_usize();
525        let endian = cx.data_layout().endian;
526        for &(offset, alloc_id) in self.provenance.ptrs().iter() {
527            let idx = offset.bytes_usize();
528            let ptr_bytes = &mut bytes[idx..idx + ptr_size];
529            let bits = read_target_uint(endian, ptr_bytes).unwrap();
530            let (ptr_prov, ptr_offset) =
531                adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts();
532            write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
533            new_provenance.push((offset, ptr_prov));
534        }
535        // Create allocation.
536        interp_ok(Allocation {
537            bytes,
538            provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
539            init_mask: self.init_mask.clone(),
540            align: self.align,
541            mutability: self.mutability,
542            extra: self.extra,
543        })
544    }
545}
546
547/// Raw accessors. Provide access to otherwise private bytes.
548impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
549    pub fn len(&self) -> usize {
550        self.bytes.len()
551    }
552
553    pub fn size(&self) -> Size {
554        Size::from_bytes(self.len())
555    }
556
557    /// Looks at a slice which may contain uninitialized bytes or provenance. This differs
558    /// from `get_bytes_with_uninit_and_ptr` in that it does no provenance checks (even on the
559    /// edges) at all.
560    /// This must not be used for reads affecting the interpreter execution.
561    pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
562        &self.bytes[range]
563    }
564
565    /// Returns the mask indicating which bytes are initialized.
566    pub fn init_mask(&self) -> &InitMask {
567        &self.init_mask
568    }
569
570    /// Returns the provenance map.
571    pub fn provenance(&self) -> &ProvenanceMap<Prov> {
572        &self.provenance
573    }
574}
575
576/// Byte accessors.
577impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
578    /// This is the entirely abstraction-violating way to just grab the raw bytes without
579    /// caring about provenance or initialization.
580    ///
581    /// This function also guarantees that the resulting pointer will remain stable
582    /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
583    /// on that.
584    #[inline]
585    pub fn get_bytes_unchecked(&self, range: AllocRange) -> &[u8] {
586        &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
587    }
588
589    /// Checks that these bytes are initialized, and then strip provenance (if possible) and return
590    /// them.
591    ///
592    /// It is the caller's responsibility to check bounds and alignment beforehand.
593    /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
594    /// on `InterpCx` instead.
595    #[inline]
596    pub fn get_bytes_strip_provenance(
597        &self,
598        cx: &impl HasDataLayout,
599        range: AllocRange,
600    ) -> AllocResult<&[u8]> {
601        self.init_mask.is_range_initialized(range).map_err(|uninit_range| {
602            AllocError::InvalidUninitBytes(Some(BadBytesAccess {
603                access: range,
604                bad: uninit_range,
605            }))
606        })?;
607        if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) {
608            // Find the provenance.
609            let (offset, _prov) = self
610                .provenance
611                .range_ptrs_get(range, cx)
612                .first()
613                .copied()
614                .expect("there must be provenance somewhere here");
615            let start = offset.max(range.start); // the pointer might begin before `range`!
616            let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`!
617            return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {
618                access: range,
619                bad: AllocRange::from(start..end),
620            })));
621        }
622        Ok(self.get_bytes_unchecked(range))
623    }
624
625    /// This is the entirely abstraction-violating way to just get mutable access to the raw bytes.
626    /// Just calling this already marks everything as defined and removes provenance, so be sure to
627    /// actually overwrite all the data there!
628    ///
629    /// It is the caller's responsibility to check bounds and alignment beforehand.
630    /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
631    /// on `InterpCx` instead.
632    pub fn get_bytes_unchecked_for_overwrite(
633        &mut self,
634        cx: &impl HasDataLayout,
635        range: AllocRange,
636    ) -> AllocResult<&mut [u8]> {
637        self.mark_init(range, true);
638        self.provenance.clear(range, cx)?;
639
640        Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
641    }
642
643    /// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases
644    /// into this memory.
645    pub fn get_bytes_unchecked_for_overwrite_ptr(
646        &mut self,
647        cx: &impl HasDataLayout,
648        range: AllocRange,
649    ) -> AllocResult<*mut [u8]> {
650        self.mark_init(range, true);
651        self.provenance.clear(range, cx)?;
652
653        assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
654        // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`.
655        let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
656        let len = range.end().bytes_usize() - range.start.bytes_usize();
657        Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
658    }
659
660    /// This gives direct mutable access to the entire buffer, just exposing their internal state
661    /// without resetting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if
662    /// `OFFSET_IS_ADDR` is true.
663    pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 {
664        assert!(Prov::OFFSET_IS_ADDR);
665        self.bytes.as_mut_ptr()
666    }
667
668    /// This gives direct immutable access to the entire buffer, just exposing their internal state
669    /// without resetting anything. Directly exposes `AllocBytes::as_ptr`. Only works if
670    /// `OFFSET_IS_ADDR` is true.
671    pub fn get_bytes_unchecked_raw(&self) -> *const u8 {
672        assert!(Prov::OFFSET_IS_ADDR);
673        self.bytes.as_ptr()
674    }
675}
676
677/// Reading and writing.
678impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
679    /// Sets the init bit for the given range.
680    fn mark_init(&mut self, range: AllocRange, is_init: bool) {
681        if range.size.bytes() == 0 {
682            return;
683        }
684        assert!(self.mutability == Mutability::Mut);
685        self.init_mask.set_range(range, is_init);
686    }
687
688    /// Reads a *non-ZST* scalar.
689    ///
690    /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine
691    /// supports that) provenance is entirely ignored.
692    ///
693    /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
694    /// for ZSTness anyway due to integer pointers being valid for ZSTs.
695    ///
696    /// It is the caller's responsibility to check bounds and alignment beforehand.
697    /// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
698    pub fn read_scalar(
699        &self,
700        cx: &impl HasDataLayout,
701        range: AllocRange,
702        read_provenance: bool,
703    ) -> AllocResult<Scalar<Prov>> {
704        // First and foremost, if anything is uninit, bail.
705        if let Err(bad) = self.init_mask.is_range_initialized(range) {
706            return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess {
707                access: range,
708                bad,
709            })));
710        }
711
712        // Get the integer part of the result. We HAVE TO check provenance before returning this!
713        let bytes = self.get_bytes_unchecked(range);
714        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
715
716        if read_provenance {
717            assert_eq!(range.size, cx.data_layout().pointer_size());
718
719            // When reading data with provenance, the easy case is finding provenance exactly where we
720            // are reading, then we can put data and provenance back together and return that.
721            if let Some(prov) = self.provenance.get_ptr(range.start) {
722                // Now we can return the bits, with their appropriate provenance.
723                let ptr = Pointer::new(prov, Size::from_bytes(bits));
724                return Ok(Scalar::from_pointer(ptr, cx));
725            }
726
727            // If we can work on pointers byte-wise, join the byte-wise provenances.
728            if Prov::OFFSET_IS_ADDR {
729                let mut prov = self.provenance.get(range.start, cx);
730                for offset in Size::from_bytes(1)..range.size {
731                    let this_prov = self.provenance.get(range.start + offset, cx);
732                    prov = Prov::join(prov, this_prov);
733                }
734                // Now use this provenance.
735                let ptr = Pointer::new(prov, Size::from_bytes(bits));
736                return Ok(Scalar::from_maybe_pointer(ptr, cx));
737            } else {
738                // Without OFFSET_IS_ADDR, the only remaining case we can handle is total absence of
739                // provenance.
740                if self.provenance.range_empty(range, cx) {
741                    return Ok(Scalar::from_uint(bits, range.size));
742                }
743                // Else we have mixed provenance, that doesn't work.
744                return Err(AllocError::ReadPartialPointer(range.start));
745            }
746        } else {
747            // We are *not* reading a pointer.
748            // If we can just ignore provenance or there is none, that's easy.
749            if Prov::OFFSET_IS_ADDR || self.provenance.range_empty(range, cx) {
750                // We just strip provenance.
751                return Ok(Scalar::from_uint(bits, range.size));
752            }
753            // There is some provenance and we don't have OFFSET_IS_ADDR. This doesn't work.
754            return Err(AllocError::ReadPointerAsInt(None));
755        }
756    }
757
758    /// Writes a *non-ZST* scalar.
759    ///
760    /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
761    /// for ZSTness anyway due to integer pointers being valid for ZSTs.
762    ///
763    /// It is the caller's responsibility to check bounds and alignment beforehand.
764    /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
765    pub fn write_scalar(
766        &mut self,
767        cx: &impl HasDataLayout,
768        range: AllocRange,
769        val: Scalar<Prov>,
770    ) -> AllocResult {
771        assert!(self.mutability == Mutability::Mut);
772
773        // `to_bits_or_ptr_internal` is the right method because we just want to store this data
774        // as-is into memory. This also double-checks that `val.size()` matches `range.size`.
775        let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
776            Right(ptr) => {
777                let (provenance, offset) = ptr.into_raw_parts();
778                (u128::from(offset.bytes()), Some(provenance))
779            }
780            Left(data) => (data, None),
781        };
782
783        let endian = cx.data_layout().endian;
784        // Yes we do overwrite all the bytes in `dst`.
785        let dst = self.get_bytes_unchecked_for_overwrite(cx, range)?;
786        write_target_uint(endian, dst, bytes).unwrap();
787
788        // See if we have to also store some provenance.
789        if let Some(provenance) = provenance {
790            assert_eq!(range.size, cx.data_layout().pointer_size());
791            self.provenance.insert_ptr(range.start, provenance, cx);
792        }
793
794        Ok(())
795    }
796
797    /// Write "uninit" to the given memory range.
798    pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
799        self.mark_init(range, false);
800        self.provenance.clear(range, cx)?;
801        Ok(())
802    }
803
804    /// Mark all bytes in the given range as initialised and reset the provenance
805    /// to wildcards. This entirely breaks the normal mechanisms for tracking
806    /// initialisation and is only provided for Miri operating in native-lib
807    /// mode. UB will be missed if the underlying bytes were not actually written to.
808    ///
809    /// If `range` is `None`, defaults to performing this on the whole allocation.
810    pub fn process_native_write(&mut self, cx: &impl HasDataLayout, range: Option<AllocRange>) {
811        let range = range.unwrap_or_else(|| AllocRange {
812            start: Size::ZERO,
813            size: Size::from_bytes(self.len()),
814        });
815        self.mark_init(range, true);
816        self.provenance.write_wildcards(cx, range);
817    }
818
819    /// Remove all provenance in the given memory range.
820    pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
821        self.provenance.clear(range, cx)?;
822        return Ok(());
823    }
824
825    /// Applies a previously prepared provenance copy.
826    /// The affected range, as defined in the parameters to `provenance().prepare_copy` is expected
827    /// to be clear of provenance.
828    ///
829    /// This is dangerous to use as it can violate internal `Allocation` invariants!
830    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
831    pub fn provenance_apply_copy(&mut self, copy: ProvenanceCopy<Prov>) {
832        self.provenance.apply_copy(copy)
833    }
834
835    /// Applies a previously prepared copy of the init mask.
836    ///
837    /// This is dangerous to use as it can violate internal `Allocation` invariants!
838    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
839    pub fn init_mask_apply_copy(&mut self, copy: InitCopy, range: AllocRange, repeat: u64) {
840        self.init_mask.apply_copy(copy, range, repeat)
841    }
842}