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