]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/interpret/mod.rs
Rollup merge of #85663 - fee1-dead:document-arc-from, r=m-ou-se
[rust.git] / compiler / rustc_middle / src / mir / interpret / mod.rs
1 //! An interpreter for MIR used in CTFE and by miri.
2
3 #[macro_export]
4 macro_rules! err_unsup {
5     ($($tt:tt)*) => {
6         $crate::mir::interpret::InterpError::Unsupported(
7             $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
8         )
9     };
10 }
11
12 #[macro_export]
13 macro_rules! err_unsup_format {
14     ($($tt:tt)*) => { err_unsup!(Unsupported(format!($($tt)*))) };
15 }
16
17 #[macro_export]
18 macro_rules! err_inval {
19     ($($tt:tt)*) => {
20         $crate::mir::interpret::InterpError::InvalidProgram(
21             $crate::mir::interpret::InvalidProgramInfo::$($tt)*
22         )
23     };
24 }
25
26 #[macro_export]
27 macro_rules! err_ub {
28     ($($tt:tt)*) => {
29         $crate::mir::interpret::InterpError::UndefinedBehavior(
30             $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
31         )
32     };
33 }
34
35 #[macro_export]
36 macro_rules! err_ub_format {
37     ($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
38 }
39
40 #[macro_export]
41 macro_rules! err_exhaust {
42     ($($tt:tt)*) => {
43         $crate::mir::interpret::InterpError::ResourceExhaustion(
44             $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
45         )
46     };
47 }
48
49 #[macro_export]
50 macro_rules! err_machine_stop {
51     ($($tt:tt)*) => {
52         $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
53     };
54 }
55
56 // In the `throw_*` macros, avoid `return` to make them work with `try {}`.
57 #[macro_export]
58 macro_rules! throw_unsup {
59     ($($tt:tt)*) => { Err::<!, _>(err_unsup!($($tt)*))? };
60 }
61
62 #[macro_export]
63 macro_rules! throw_unsup_format {
64     ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
65 }
66
67 #[macro_export]
68 macro_rules! throw_inval {
69     ($($tt:tt)*) => { Err::<!, _>(err_inval!($($tt)*))? };
70 }
71
72 #[macro_export]
73 macro_rules! throw_ub {
74     ($($tt:tt)*) => { Err::<!, _>(err_ub!($($tt)*))? };
75 }
76
77 #[macro_export]
78 macro_rules! throw_ub_format {
79     ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
80 }
81
82 #[macro_export]
83 macro_rules! throw_exhaust {
84     ($($tt:tt)*) => { Err::<!, _>(err_exhaust!($($tt)*))? };
85 }
86
87 #[macro_export]
88 macro_rules! throw_machine_stop {
89     ($($tt:tt)*) => { Err::<!, _>(err_machine_stop!($($tt)*))? };
90 }
91
92 mod allocation;
93 mod error;
94 mod pointer;
95 mod queries;
96 mod value;
97
98 use std::convert::TryFrom;
99 use std::fmt;
100 use std::io;
101 use std::io::{Read, Write};
102 use std::num::NonZeroU32;
103 use std::sync::atomic::{AtomicU32, Ordering};
104
105 use rustc_ast::LitKind;
106 use rustc_data_structures::fx::FxHashMap;
107 use rustc_data_structures::sync::{HashMapExt, Lock};
108 use rustc_data_structures::tiny_list::TinyList;
109 use rustc_hir::def_id::DefId;
110 use rustc_macros::HashStable;
111 use rustc_middle::ty::print::with_no_trimmed_paths;
112 use rustc_serialize::{Decodable, Encodable};
113 use rustc_target::abi::Endian;
114
115 use crate::mir;
116 use crate::ty::codec::{TyDecoder, TyEncoder};
117 use crate::ty::subst::GenericArgKind;
118 use crate::ty::{self, Instance, Ty, TyCtxt};
119
120 pub use self::error::{
121     struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
122     InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
123     ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
124 };
125
126 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
127
128 pub use self::allocation::{alloc_range, AllocRange, Allocation, InitMask, Relocations};
129
130 pub use self::pointer::{Pointer, PointerArithmetic};
131
132 /// Uniquely identifies one of the following:
133 /// - A constant
134 /// - A static
135 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
136 #[derive(HashStable, Lift)]
137 pub struct GlobalId<'tcx> {
138     /// For a constant or static, the `Instance` of the item itself.
139     /// For a promoted global, the `Instance` of the function they belong to.
140     pub instance: ty::Instance<'tcx>,
141
142     /// The index for promoted globals within their function's `mir::Body`.
143     pub promoted: Option<mir::Promoted>,
144 }
145
146 impl GlobalId<'tcx> {
147     pub fn display(self, tcx: TyCtxt<'tcx>) -> String {
148         let instance_name = with_no_trimmed_paths(|| tcx.def_path_str(self.instance.def.def_id()));
149         if let Some(promoted) = self.promoted {
150             format!("{}::{:?}", instance_name, promoted)
151         } else {
152             instance_name
153         }
154     }
155 }
156
157 /// Input argument for `tcx.lit_to_const`.
158 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)]
159 pub struct LitToConstInput<'tcx> {
160     /// The absolute value of the resultant constant.
161     pub lit: &'tcx LitKind,
162     /// The type of the constant.
163     pub ty: Ty<'tcx>,
164     /// If the constant is negative.
165     pub neg: bool,
166 }
167
168 /// Error type for `tcx.lit_to_const`.
169 #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
170 pub enum LitToConstError {
171     /// The literal's inferred type did not match the expected `ty` in the input.
172     /// This is used for graceful error handling (`delay_span_bug`) in
173     /// type checking (`Const::from_anon_const`).
174     TypeError,
175     UnparseableFloat,
176     Reported,
177 }
178
179 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
180 pub struct AllocId(pub u64);
181
182 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
183 // all the Miri types.
184 impl fmt::Debug for AllocId {
185     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186         if f.alternate() { write!(f, "a{}", self.0) } else { write!(f, "alloc{}", self.0) }
187     }
188 }
189
190 impl fmt::Display for AllocId {
191     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192         fmt::Debug::fmt(self, f)
193     }
194 }
195
196 #[derive(TyDecodable, TyEncodable)]
197 enum AllocDiscriminant {
198     Alloc,
199     Fn,
200     Static,
201 }
202
203 pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>(
204     encoder: &mut E,
205     tcx: TyCtxt<'tcx>,
206     alloc_id: AllocId,
207 ) -> Result<(), E::Error> {
208     match tcx.global_alloc(alloc_id) {
209         GlobalAlloc::Memory(alloc) => {
210             trace!("encoding {:?} with {:#?}", alloc_id, alloc);
211             AllocDiscriminant::Alloc.encode(encoder)?;
212             alloc.encode(encoder)?;
213         }
214         GlobalAlloc::Function(fn_instance) => {
215             trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
216             AllocDiscriminant::Fn.encode(encoder)?;
217             fn_instance.encode(encoder)?;
218         }
219         GlobalAlloc::Static(did) => {
220             assert!(!tcx.is_thread_local_static(did));
221             // References to statics doesn't need to know about their allocations,
222             // just about its `DefId`.
223             AllocDiscriminant::Static.encode(encoder)?;
224             did.encode(encoder)?;
225         }
226     }
227     Ok(())
228 }
229
230 // Used to avoid infinite recursion when decoding cyclic allocations.
231 type DecodingSessionId = NonZeroU32;
232
233 #[derive(Clone)]
234 enum State {
235     Empty,
236     InProgressNonAlloc(TinyList<DecodingSessionId>),
237     InProgress(TinyList<DecodingSessionId>, AllocId),
238     Done(AllocId),
239 }
240
241 pub struct AllocDecodingState {
242     // For each `AllocId`, we keep track of which decoding state it's currently in.
243     decoding_state: Vec<Lock<State>>,
244     // The offsets of each allocation in the data stream.
245     data_offsets: Vec<u32>,
246 }
247
248 impl AllocDecodingState {
249     #[inline]
250     pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
251         static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
252         let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
253
254         // Make sure this is never zero.
255         let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap();
256
257         AllocDecodingSession { state: self, session_id }
258     }
259
260     pub fn new(data_offsets: Vec<u32>) -> Self {
261         let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()];
262
263         Self { decoding_state, data_offsets }
264     }
265 }
266
267 #[derive(Copy, Clone)]
268 pub struct AllocDecodingSession<'s> {
269     state: &'s AllocDecodingState,
270     session_id: DecodingSessionId,
271 }
272
273 impl<'s> AllocDecodingSession<'s> {
274     /// Decodes an `AllocId` in a thread-safe way.
275     pub fn decode_alloc_id<D>(&self, decoder: &mut D) -> Result<AllocId, D::Error>
276     where
277         D: TyDecoder<'tcx>,
278     {
279         // Read the index of the allocation.
280         let idx = usize::try_from(decoder.read_u32()?).unwrap();
281         let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
282
283         // Decode the `AllocDiscriminant` now so that we know if we have to reserve an
284         // `AllocId`.
285         let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
286             let alloc_kind = AllocDiscriminant::decode(decoder)?;
287             Ok((alloc_kind, decoder.position()))
288         })?;
289
290         // Check the decoding state to see if it's already decoded or if we should
291         // decode it here.
292         let alloc_id = {
293             let mut entry = self.state.decoding_state[idx].lock();
294
295             match *entry {
296                 State::Done(alloc_id) => {
297                     return Ok(alloc_id);
298                 }
299                 ref mut entry @ State::Empty => {
300                     // We are allowed to decode.
301                     match alloc_kind {
302                         AllocDiscriminant::Alloc => {
303                             // If this is an allocation, we need to reserve an
304                             // `AllocId` so we can decode cyclic graphs.
305                             let alloc_id = decoder.tcx().reserve_alloc_id();
306                             *entry =
307                                 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
308                             Some(alloc_id)
309                         }
310                         AllocDiscriminant::Fn | AllocDiscriminant::Static => {
311                             // Fns and statics cannot be cyclic, and their `AllocId`
312                             // is determined later by interning.
313                             *entry =
314                                 State::InProgressNonAlloc(TinyList::new_single(self.session_id));
315                             None
316                         }
317                     }
318                 }
319                 State::InProgressNonAlloc(ref mut sessions) => {
320                     if sessions.contains(&self.session_id) {
321                         bug!("this should be unreachable");
322                     } else {
323                         // Start decoding concurrently.
324                         sessions.insert(self.session_id);
325                         None
326                     }
327                 }
328                 State::InProgress(ref mut sessions, alloc_id) => {
329                     if sessions.contains(&self.session_id) {
330                         // Don't recurse.
331                         return Ok(alloc_id);
332                     } else {
333                         // Start decoding concurrently.
334                         sessions.insert(self.session_id);
335                         Some(alloc_id)
336                     }
337                 }
338             }
339         };
340
341         // Now decode the actual data.
342         let alloc_id = decoder.with_position(pos, |decoder| {
343             match alloc_kind {
344                 AllocDiscriminant::Alloc => {
345                     let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder)?;
346                     // We already have a reserved `AllocId`.
347                     let alloc_id = alloc_id.unwrap();
348                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
349                     decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc);
350                     Ok(alloc_id)
351                 }
352                 AllocDiscriminant::Fn => {
353                     assert!(alloc_id.is_none());
354                     trace!("creating fn alloc ID");
355                     let instance = ty::Instance::decode(decoder)?;
356                     trace!("decoded fn alloc instance: {:?}", instance);
357                     let alloc_id = decoder.tcx().create_fn_alloc(instance);
358                     Ok(alloc_id)
359                 }
360                 AllocDiscriminant::Static => {
361                     assert!(alloc_id.is_none());
362                     trace!("creating extern static alloc ID");
363                     let did = <DefId as Decodable<D>>::decode(decoder)?;
364                     trace!("decoded static def-ID: {:?}", did);
365                     let alloc_id = decoder.tcx().create_static_alloc(did);
366                     Ok(alloc_id)
367                 }
368             }
369         })?;
370
371         self.state.decoding_state[idx].with_lock(|entry| {
372             *entry = State::Done(alloc_id);
373         });
374
375         Ok(alloc_id)
376     }
377 }
378
379 /// An allocation in the global (tcx-managed) memory can be either a function pointer,
380 /// a static, or a "real" allocation with some data in it.
381 #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
382 pub enum GlobalAlloc<'tcx> {
383     /// The alloc ID is used as a function pointer.
384     Function(Instance<'tcx>),
385     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
386     /// This is also used to break the cycle in recursive statics.
387     Static(DefId),
388     /// The alloc ID points to memory.
389     Memory(&'tcx Allocation),
390 }
391
392 impl GlobalAlloc<'tcx> {
393     /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
394     #[track_caller]
395     #[inline]
396     pub fn unwrap_memory(&self) -> &'tcx Allocation {
397         match *self {
398             GlobalAlloc::Memory(mem) => mem,
399             _ => bug!("expected memory, got {:?}", self),
400         }
401     }
402
403     /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Function`
404     #[track_caller]
405     #[inline]
406     pub fn unwrap_fn(&self) -> Instance<'tcx> {
407         match *self {
408             GlobalAlloc::Function(instance) => instance,
409             _ => bug!("expected function, got {:?}", self),
410         }
411     }
412 }
413
414 crate struct AllocMap<'tcx> {
415     /// Maps `AllocId`s to their corresponding allocations.
416     alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
417
418     /// Used to ensure that statics and functions only get one associated `AllocId`.
419     /// Should never contain a `GlobalAlloc::Memory`!
420     //
421     // FIXME: Should we just have two separate dedup maps for statics and functions each?
422     dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
423
424     /// The `AllocId` to assign to the next requested ID.
425     /// Always incremented; never gets smaller.
426     next_id: AllocId,
427 }
428
429 impl<'tcx> AllocMap<'tcx> {
430     crate fn new() -> Self {
431         AllocMap { alloc_map: Default::default(), dedup: Default::default(), next_id: AllocId(0) }
432     }
433     fn reserve(&mut self) -> AllocId {
434         let next = self.next_id;
435         self.next_id.0 = self.next_id.0.checked_add(1).expect(
436             "You overflowed a u64 by incrementing by 1... \
437              You've just earned yourself a free drink if we ever meet. \
438              Seriously, how did you do that?!",
439         );
440         next
441     }
442 }
443
444 impl<'tcx> TyCtxt<'tcx> {
445     /// Obtains a new allocation ID that can be referenced but does not
446     /// yet have an allocation backing it.
447     ///
448     /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
449     /// an `AllocId` from a query.
450     pub fn reserve_alloc_id(self) -> AllocId {
451         self.alloc_map.lock().reserve()
452     }
453
454     /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
455     /// Should only be used for function pointers and statics, we don't want
456     /// to dedup IDs for "real" memory!
457     fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
458         let mut alloc_map = self.alloc_map.lock();
459         match alloc {
460             GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {}
461             GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
462         }
463         if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
464             return alloc_id;
465         }
466         let id = alloc_map.reserve();
467         debug!("creating alloc {:?} with id {}", alloc, id);
468         alloc_map.alloc_map.insert(id, alloc.clone());
469         alloc_map.dedup.insert(alloc, id);
470         id
471     }
472
473     /// Generates an `AllocId` for a static or return a cached one in case this function has been
474     /// called on the same static before.
475     pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
476         self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
477     }
478
479     /// Generates an `AllocId` for a function.  Depending on the function type,
480     /// this might get deduplicated or assigned a new ID each time.
481     pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
482         // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
483         // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
484         // duplicated across crates.
485         // We thus generate a new `AllocId` for every mention of a function. This means that
486         // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
487         // However, formatting code relies on function identity (see #58320), so we only do
488         // this for generic functions.  Lifetime parameters are ignored.
489         let is_generic = instance
490             .substs
491             .into_iter()
492             .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
493         if is_generic {
494             // Get a fresh ID.
495             let mut alloc_map = self.alloc_map.lock();
496             let id = alloc_map.reserve();
497             alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance));
498             id
499         } else {
500             // Deduplicate.
501             self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
502         }
503     }
504
505     /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
506     /// `Allocation` with a different `AllocId`.
507     /// Statics with identical content will still point to the same `Allocation`, i.e.,
508     /// their data will be deduplicated through `Allocation` interning -- but they
509     /// are different places in memory and as such need different IDs.
510     pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId {
511         let id = self.reserve_alloc_id();
512         self.set_alloc_id_memory(id, mem);
513         id
514     }
515
516     /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
517     /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
518     /// illegal and will likely ICE.
519     /// This function exists to allow const eval to detect the difference between evaluation-
520     /// local dangling pointers and allocations in constants/statics.
521     #[inline]
522     pub fn get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
523         self.alloc_map.lock().alloc_map.get(&id).cloned()
524     }
525
526     #[inline]
527     #[track_caller]
528     /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in
529     /// constants (as all constants must pass interning and validation that check for dangling
530     /// ids), this function is frequently used throughout rustc, but should not be used within
531     /// the miri engine.
532     pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
533         match self.get_global_alloc(id) {
534             Some(alloc) => alloc,
535             None => bug!("could not find allocation for {}", id),
536         }
537     }
538
539     /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
540     /// call this function twice, even with the same `Allocation` will ICE the compiler.
541     pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) {
542         if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
543             bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
544         }
545     }
546
547     /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
548     /// twice for the same `(AllocId, Allocation)` pair.
549     fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) {
550         self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
551     }
552 }
553
554 ////////////////////////////////////////////////////////////////////////////////
555 // Methods to access integers in the target endianness
556 ////////////////////////////////////////////////////////////////////////////////
557
558 #[inline]
559 pub fn write_target_uint(
560     endianness: Endian,
561     mut target: &mut [u8],
562     data: u128,
563 ) -> Result<(), io::Error> {
564     // This u128 holds an "any-size uint" (since smaller uints can fits in it)
565     // So we do not write all bytes of the u128, just the "payload".
566     match endianness {
567         Endian::Little => target.write(&data.to_le_bytes())?,
568         Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?,
569     };
570     debug_assert!(target.len() == 0); // We should have filled the target buffer.
571     Ok(())
572 }
573
574 #[inline]
575 pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> {
576     // This u128 holds an "any-size uint" (since smaller uints can fits in it)
577     let mut buf = [0u8; std::mem::size_of::<u128>()];
578     // So we do not read exactly 16 bytes into the u128, just the "payload".
579     let uint = match endianness {
580         Endian::Little => {
581             source.read(&mut buf)?;
582             Ok(u128::from_le_bytes(buf))
583         }
584         Endian::Big => {
585             source.read(&mut buf[16 - source.len()..])?;
586             Ok(u128::from_be_bytes(buf))
587         }
588     };
589     debug_assert!(source.len() == 0); // We should have consumed the source buffer.
590     uint
591 }