]> git.lizzy.rs Git - rust.git/blobdiff - src/machine.rs
rename track-raw-pointers flag to tag-raw-pointers
[rust.git] / src / machine.rs
index 4f643e7f509178a4c7d3af74065a850682e5750a..201854e76fa46052bfed004367fb6fc4f7dd47de 100644 (file)
     mir,
     ty::{
         self,
-        layout::{LayoutCx, LayoutError, TyAndLayout},
-        TyCtxt,
+        layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
+        Instance, TyCtxt,
     },
 };
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{LayoutOf, Size};
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
 use crate::*;
@@ -52,9 +52,10 @@ pub struct FrameData<'tcx> {
 impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         // Omitting `timing`, it does not support `Debug`.
+        let FrameData { call_id, catch_unwind, timing: _ } = self;
         f.debug_struct("FrameData")
-            .field("call_id", &self.call_id)
-            .field("catch_unwind", &self.catch_unwind)
+            .field("call_id", call_id)
+            .field("catch_unwind", catch_unwind)
             .finish()
     }
 }
@@ -118,6 +119,39 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+/// Pointer provenance (tag).
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct Tag {
+    pub alloc_id: AllocId,
+    /// Stacked Borrows tag.
+    pub sb: SbTag,
+}
+
+impl Provenance for Tag {
+    /// We use absolute addresses in the `offset` of a `Pointer<Tag>`.
+    const OFFSET_IS_ADDR: bool = true;
+
+    /// We cannot err on partial overwrites, it happens too often in practice (due to unions).
+    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false;
+
+    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (tag, addr) = ptr.into_parts(); // address is absolute
+        write!(f, "0x{:x}", addr.bytes())?;
+        // Forward `alternate` flag to `alloc_id` printing.
+        if f.alternate() {
+            write!(f, "[{:#?}]", tag.alloc_id)?;
+        } else {
+            write!(f, "[{:?}]", tag.alloc_id)?;
+        }
+        // Print Stacked Borrows tag.
+        write!(f, "{:?}", tag.sb)
+    }
+
+    fn get_alloc_id(self) -> AllocId {
+        self.alloc_id
+    }
+}
+
 /// Extra per-allocation data
 #[derive(Debug, Clone)]
 pub struct AllocExtra {
@@ -135,8 +169,8 @@ pub struct MemoryExtra {
     pub data_race: Option<data_race::MemoryExtra>,
     pub intptrcast: intptrcast::MemoryExtra,
 
-    /// Mapping extern static names to their canonical allocation.
-    extern_statics: FxHashMap<Symbol, AllocId>,
+    /// Mapping extern static names to their base pointer.
+    extern_statics: FxHashMap<Symbol, Pointer<Tag>>,
 
     /// The random number generator used for resolving non-determinism.
     /// Needs to be queried by ptr_to_int, hence needs interior mutability.
@@ -160,7 +194,7 @@ pub fn new(config: &MiriConfig) -> Self {
             Some(RefCell::new(stacked_borrows::GlobalState::new(
                 config.tracked_pointer_tag,
                 config.tracked_call_id,
-                config.track_raw,
+                config.tag_raw,
             )))
         } else {
             None
@@ -182,11 +216,10 @@ pub fn new(config: &MiriConfig) -> Self {
     fn add_extern_static<'tcx, 'mir>(
         this: &mut MiriEvalContext<'mir, 'tcx>,
         name: &str,
-        ptr: Scalar<Tag>,
+        ptr: Pointer<Option<Tag>>,
     ) {
-        let ptr = ptr.assert_ptr();
-        assert_eq!(ptr.offset, Size::ZERO);
-        this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr.alloc_id).unwrap();
+        let ptr = ptr.into_pointer_or_addr().unwrap();
+        this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
     }
 
     /// Sets up the "extern statics" for this machine.
@@ -198,7 +231,7 @@ pub fn init_extern_statics<'tcx, 'mir>(
                 // "__cxa_thread_atexit_impl"
                 // This should be all-zero, pointer-sized.
                 let layout = this.machine.layouts.usize;
-                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into());
+                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
                 this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
                 Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr);
                 // "environ"
@@ -212,7 +245,7 @@ pub fn init_extern_statics<'tcx, 'mir>(
                 // "_tls_used"
                 // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
                 let layout = this.machine.layouts.u8;
-                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into());
+                let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
                 this.write_scalar(Scalar::from_u8(0), &place.into())?;
                 Self::add_extern_static(this, "_tls_used", place.ptr);
             }
@@ -256,20 +289,27 @@ pub struct Evaluator<'mir, 'tcx> {
     /// Program arguments (`Option` because we can only initialize them after creating the ecx).
     /// These are *pointers* to argc/argv because macOS.
     /// We also need the full command line as one string because of Windows.
-    pub(crate) argc: Option<Scalar<Tag>>,
-    pub(crate) argv: Option<Scalar<Tag>>,
-    pub(crate) cmd_line: Option<Scalar<Tag>>,
+    pub(crate) argc: Option<MemPlace<Tag>>,
+    pub(crate) argv: Option<MemPlace<Tag>>,
+    pub(crate) cmd_line: Option<MemPlace<Tag>>,
 
     /// TLS state.
     pub(crate) tls: TlsData<'tcx>,
 
-    /// If enabled, the `env_vars` field is populated with the host env vars during initialization
-    /// and random number generation is delegated to the host.
-    pub(crate) communicate: bool,
+    /// What should Miri do when an op requires communicating with the host,
+    /// such as accessing host env vars, random number generation, and
+    /// file system access.
+    pub(crate) isolated_op: IsolatedOp,
 
     /// Whether to enforce the validity invariant.
     pub(crate) validate: bool,
 
+    /// Whether to enforce validity (e.g., initialization) of integers and floats.
+    pub(crate) enforce_number_validity: bool,
+
+    /// Whether to enforce [ABI](Abi) of function calls.
+    pub(crate) enforce_abi: bool,
+
     pub(crate) file_handler: shims::posix::FileHandler,
     pub(crate) dir_handler: shims::posix::DirHandler,
 
@@ -291,6 +331,15 @@ pub struct Evaluator<'mir, 'tcx> {
     /// Used with `profiler` to cache the `StringId`s for event names
     /// uesd with `measureme`.
     string_cache: FxHashMap<String, measureme::StringId>,
+
+    /// Cache of `Instance` exported under the given `Symbol` name.
+    /// `None` means no `Instance` exported under the given name is found.
+    pub(crate) exported_symbols_cache: FxHashMap<Symbol, Option<Instance<'tcx>>>,
+
+    /// Whether to raise a panic in the context of the evaluated process when unsupported
+    /// functionality is encountered. If `false`, an error is propagated in the Miri application context
+    /// instead (default behavior)
+    pub(crate) panic_on_unsupported: bool,
 }
 
 impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
@@ -308,8 +357,10 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
             argv: None,
             cmd_line: None,
             tls: TlsData::default(),
-            communicate: config.communicate,
+            isolated_op: config.isolated_op,
             validate: config.validate,
+            enforce_number_validity: config.check_number_validity,
+            enforce_abi: config.check_abi,
             file_handler: Default::default(),
             dir_handler: Default::default(),
             time_anchor: Instant::now(),
@@ -318,8 +369,14 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
             static_roots: Vec::new(),
             profiler,
             string_cache: Default::default(),
+            exported_symbols_cache: FxHashMap::default(),
+            panic_on_unsupported: config.panic_on_unsupported,
         }
     }
+
+    pub(crate) fn communicate(&self) -> bool {
+        self.isolated_op == IsolatedOp::Allow
+    }
 }
 
 /// A rustc InterpCx for Miri.
@@ -356,6 +413,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
 
     const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global);
 
+    const PANIC_ON_ALLOC_FAIL: bool = false;
+
     #[inline(always)]
     fn enforce_alignment(memory_extra: &MemoryExtra) -> bool {
         memory_extra.check_alignment != AlignmentCheck::None
@@ -371,6 +430,16 @@ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         ecx.machine.validate
     }
 
+    #[inline(always)]
+    fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.machine.enforce_number_validity
+    }
+
+    #[inline(always)]
+    fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.machine.enforce_abi
+    }
+
     #[inline(always)]
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -397,7 +466,7 @@ fn call_extra_fn(
 
     #[inline(always)]
     fn call_intrinsic(
-        ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>,
+        ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Tag>],
         ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
@@ -422,7 +491,7 @@ fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tc
 
     #[inline(always)]
     fn binary_ptr_op(
-        ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>,
+        ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
         left: &ImmTy<'tcx, Tag>,
         right: &ImmTy<'tcx, Tag>,
@@ -459,82 +528,107 @@ fn box_alloc(
         Ok(())
     }
 
-    fn thread_local_static_alloc_id(
+    fn thread_local_static_base_pointer(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         def_id: DefId,
-    ) -> InterpResult<'tcx, AllocId> {
-        ecx.get_or_create_thread_local_alloc_id(def_id)
+    ) -> InterpResult<'tcx, Pointer<Tag>> {
+        ecx.get_or_create_thread_local_alloc(def_id)
     }
 
-    fn extern_static_alloc_id(
+    fn extern_static_base_pointer(
         memory: &Memory<'mir, 'tcx, Self>,
         def_id: DefId,
-    ) -> InterpResult<'tcx, AllocId> {
+    ) -> InterpResult<'tcx, Pointer<Tag>> {
         let attrs = memory.tcx.get_attrs(def_id);
         let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) {
             Some(name) => name,
             None => memory.tcx.item_name(def_id),
         };
-        if let Some(&id) = memory.extra.extern_statics.get(&link_name) {
-            Ok(id)
+        if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) {
+            Ok(ptr)
         } else {
             throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id)
         }
     }
 
     fn init_allocation_extra<'b>(
-        memory_extra: &MemoryExtra,
+        mem: &Memory<'mir, 'tcx, Self>,
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
-        if Some(id) == memory_extra.tracked_alloc_id {
+    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>> {
+        if Some(id) == mem.extra.tracked_alloc_id {
             register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id));
         }
 
         let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
         let alloc = alloc.into_owned();
-        let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows {
-            let (stacks, base_tag) =
-                Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind);
-            (Some(stacks), base_tag)
+        let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows {
+            Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind))
         } else {
-            // No stacks, no tag.
-            (None, Tag::Untagged)
+            None
         };
-        let race_alloc = if let Some(data_race) = &memory_extra.data_race {
+        let race_alloc = if let Some(data_race) = &mem.extra.data_race {
             Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind))
         } else {
             None
         };
-        let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut());
-        let alloc: Allocation<Tag, Self::AllocExtra> = alloc.with_tags_and_extra(
-            |alloc| {
-                if let Some(stacked_borrows) = &mut stacked_borrows {
-                    // Only globals may already contain pointers at this point
-                    assert_eq!(kind, MiriMemoryKind::Global.into());
-                    stacked_borrows.global_base_ptr(alloc)
-                } else {
-                    Tag::Untagged
-                }
-            },
+        let alloc: Allocation<Tag, Self::AllocExtra> = alloc.convert_tag_add_extra(
+            &mem.tcx,
             AllocExtra { stacked_borrows: stacks, data_race: race_alloc },
+            |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr),
         );
-        (Cow::Owned(alloc), base_tag)
+        Cow::Owned(alloc)
+    }
+
+    fn tag_alloc_base_pointer(
+        mem: &Memory<'mir, 'tcx, Self>,
+        ptr: Pointer<AllocId>,
+    ) -> Pointer<Tag> {
+        let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr);
+        let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows {
+            stacked_borrows.borrow_mut().base_tag(ptr.provenance)
+        } else {
+            SbTag::Untagged
+        };
+        Pointer::new(Tag { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr))
+    }
+
+    #[inline(always)]
+    fn ptr_from_addr(
+        mem: &Memory<'mir, 'tcx, Self>,
+        addr: u64,
+    ) -> Pointer<Option<Self::PointerTag>> {
+        intptrcast::GlobalState::ptr_from_addr(addr, mem)
+    }
+
+    /// Convert a pointer with provenance into an allocation-offset pair,
+    /// or a `None` with an absolute address if that conversion is not possible.
+    fn ptr_get_alloc(
+        mem: &Memory<'mir, 'tcx, Self>,
+        ptr: Pointer<Self::PointerTag>,
+    ) -> (AllocId, Size) {
+        let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr);
+        (ptr.provenance.alloc_id, rel)
     }
 
     #[inline(always)]
     fn memory_read(
         memory_extra: &Self::MemoryExtra,
         alloc_extra: &AllocExtra,
-        ptr: Pointer<Tag>,
-        size: Size,
+        tag: Tag,
+        range: AllocRange,
     ) -> InterpResult<'tcx> {
         if let Some(data_race) = &alloc_extra.data_race {
-            data_race.read(ptr, size, memory_extra.data_race.as_ref().unwrap())?;
+            data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?;
         }
         if let Some(stacked_borrows) = &alloc_extra.stacked_borrows {
-            stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap())
+            stacked_borrows.memory_read(
+                tag.alloc_id,
+                tag.sb,
+                range,
+                memory_extra.stacked_borrows.as_ref().unwrap(),
+            )
         } else {
             Ok(())
         }
@@ -544,16 +638,17 @@ fn memory_read(
     fn memory_written(
         memory_extra: &mut Self::MemoryExtra,
         alloc_extra: &mut AllocExtra,
-        ptr: Pointer<Tag>,
-        size: Size,
+        tag: Tag,
+        range: AllocRange,
     ) -> InterpResult<'tcx> {
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?;
+            data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?;
         }
         if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
             stacked_borrows.memory_written(
-                ptr,
-                size,
+                tag.alloc_id,
+                tag.sb,
+                range,
                 memory_extra.stacked_borrows.as_mut().unwrap(),
             )
         } else {
@@ -565,19 +660,20 @@ fn memory_written(
     fn memory_deallocated(
         memory_extra: &mut Self::MemoryExtra,
         alloc_extra: &mut AllocExtra,
-        ptr: Pointer<Tag>,
-        size: Size,
+        tag: Tag,
+        range: AllocRange,
     ) -> InterpResult<'tcx> {
-        if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id {
-            register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id));
+        if Some(tag.alloc_id) == memory_extra.tracked_alloc_id {
+            register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?;
+            data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?;
         }
         if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
             stacked_borrows.memory_deallocated(
-                ptr,
-                size,
+                tag.alloc_id,
+                tag.sb,
+                range,
                 memory_extra.stacked_borrows.as_mut().unwrap(),
             )
         } else {
@@ -585,26 +681,6 @@ fn memory_deallocated(
         }
     }
 
-    fn after_static_mem_initialized(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        ptr: Pointer<Self::PointerTag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        if ecx.memory.extra.data_race.is_some() {
-            ecx.reset_vector_clocks(ptr, size)?;
-        }
-        Ok(())
-    }
-
-    #[inline(always)]
-    fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag {
-        if let Some(stacked_borrows) = &memory_extra.stacked_borrows {
-            stacked_borrows.borrow_mut().global_base_ptr(id)
-        } else {
-            Tag::Untagged
-        }
-    }
-
     #[inline(always)]
     fn retag(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -673,20 +749,4 @@ fn after_stack_pop(
         }
         res
     }
-
-    #[inline(always)]
-    fn int_to_ptr(
-        memory: &Memory<'mir, 'tcx, Self>,
-        int: u64,
-    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
-        intptrcast::GlobalState::int_to_ptr(int, memory)
-    }
-
-    #[inline(always)]
-    fn ptr_to_int(
-        memory: &Memory<'mir, 'tcx, Self>,
-        ptr: Pointer<Self::PointerTag>,
-    ) -> InterpResult<'tcx, u64> {
-        intptrcast::GlobalState::ptr_to_int(ptr, memory)
-    }
 }