]> git.lizzy.rs Git - rust.git/blobdiff - src/stacked_borrows.rs
env shim: make sure we clean up all the memory we allocate
[rust.git] / src / stacked_borrows.rs
index 7bb7dd6cec11b52bdf8a165dec3d97fc8498df30..c130abf0576be7da1d5eb53fb8a1d9be4cf2a341 100644 (file)
@@ -2,15 +2,14 @@
 //! for further information.
 
 use std::cell::RefCell;
-use std::collections::{HashMap, HashSet};
 use std::fmt;
 use std::num::NonZeroU64;
 use std::rc::Rc;
 
-use rustc_hir::Mutability;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc::mir::RetagKind;
 use rustc::ty::{self, layout::Size};
-use rustc_mir::interpret::InterpError;
+use rustc_hir::Mutability;
 
 use crate::*;
 
@@ -97,11 +96,11 @@ pub struct GlobalState {
     /// Table storing the "base" tag for each allocation.
     /// The base tag is the one used for the initial pointer.
     /// We need this in a separate table to handle cyclic statics.
-    base_ptr_ids: HashMap<AllocId, Tag>,
+    base_ptr_ids: FxHashMap<AllocId, Tag>,
     /// Next unused call ID (for protectors).
     next_call_id: CallId,
     /// Those call IDs corresponding to functions that are still running.
-    active_calls: HashSet<CallId>,
+    active_calls: FxHashSet<CallId>,
     /// The id to trace in this execution run
     tracked_pointer_tag: Option<PtrId>,
 }
@@ -154,9 +153,9 @@ impl GlobalState {
     pub fn new(tracked_pointer_tag: Option<PtrId>) -> Self {
         GlobalState {
             next_ptr_id: NonZeroU64::new(1).unwrap(),
-            base_ptr_ids: HashMap::default(),
+            base_ptr_ids: FxHashMap::default(),
             next_call_id: NonZeroU64::new(1).unwrap(),
-            active_calls: HashSet::default(),
+            active_calls: FxHashSet::default(),
             tracked_pointer_tag,
         }
     }
@@ -183,7 +182,7 @@ fn is_active(&self, id: CallId) -> bool {
         self.active_calls.contains(&id)
     }
 
-    pub fn static_base_ptr(&mut self, id: AllocId) -> Tag {
+    pub fn global_base_ptr(&mut self, id: AllocId) -> Tag {
         self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| {
             let tag = Tag::Tagged(self.new_ptr());
             trace!("New allocation {:?} has base tag {:?}", id, tag);
@@ -193,6 +192,14 @@ pub fn static_base_ptr(&mut self, id: AllocId) -> Tag {
     }
 }
 
+/// Error reporting
+fn err_sb_ub(msg: String) -> InterpError<'static> {
+    err_machine_stop!(TerminationInfo::ExperimentalUb {
+        msg,
+        url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"),
+    })
+}
+
 // # Stacked Borrows Core Begin
 
 /// We need to make at least the following things true:
@@ -267,26 +274,21 @@ fn find_first_write_incompatible(&self, granting: usize) -> usize {
     fn check_protector(item: &Item, tag: Option<Tag>, global: &GlobalState) -> InterpResult<'tcx> {
         if let Tag::Tagged(id) = item.tag {
             if Some(id) == global.tracked_pointer_tag {
-                register_err(
-                    InterpError::MachineStop(Box::new(TerminationInfo::PoppedTrackedPointerTag(
-                        item.clone(),
-                    )))
-                    .into(),
-                );
+                register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone()));
             }
         }
         if let Some(call) = item.protector {
             if global.is_active(call) {
                 if let Some(tag) = tag {
-                    throw_ub!(UbExperimental(format!(
+                    Err(err_sb_ub(format!(
                         "not granting access to tag {:?} because incompatible item is protected: {:?}",
                         tag, item
-                    )));
+                    )))?
                 } else {
-                    throw_ub!(UbExperimental(format!(
+                    Err(err_sb_ub(format!(
                         "deallocating while item is protected: {:?}",
                         item
-                    )));
+                    )))?
                 }
             }
         }
@@ -299,9 +301,12 @@ fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> Inte
         // Two main steps: Find granting item, remove incompatible items above.
 
         // Step 1: Find granting item.
-        let granting_idx = self.find_granting(access, tag).ok_or_else(|| err_ub!(UbExperimental(
-            format!("no item granting {} to tag {:?} found in borrow stack.", access, tag),
-        )))?;
+        let granting_idx = self.find_granting(access, tag).ok_or_else(|| {
+            err_sb_ub(format!(
+                "no item granting {} to tag {:?} found in borrow stack.",
+                access, tag
+            ))
+        })?;
 
         // Step 2: Remove incompatible items above them.  Make sure we do not remove protected
         // items.  Behavior differs for reads and writes.
@@ -340,10 +345,12 @@ fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> Inte
     /// active protectors at all because we will remove all items.
     fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> {
         // Step 1: Find granting item.
-        self.find_granting(AccessKind::Write, tag).ok_or_else(|| err_ub!(UbExperimental(format!(
-            "no item granting write access for deallocation to tag {:?} found in borrow stack",
-            tag,
-        ))))?;
+        self.find_granting(AccessKind::Write, tag).ok_or_else(|| {
+            err_sb_ub(format!(
+                "no item granting write access for deallocation to tag {:?} found in borrow stack",
+                tag,
+            ))
+        })?;
 
         // Step 2: Remove all items.  Also checks for protectors.
         for item in self.borrows.drain(..).rev() {
@@ -364,10 +371,10 @@ fn grant(&mut self, derived_from: Tag, new: Item, global: &GlobalState) -> Inter
         // Now we figure out which item grants our parent (`derived_from`) this kind of access.
         // We use that to determine where to put the new item.
         let granting_idx = self.find_granting(access, derived_from)
-            .ok_or_else(|| err_ub!(UbExperimental(format!(
+            .ok_or_else(|| err_sb_ub(format!(
                 "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack",
                 new.perm, derived_from,
-            ))))?;
+            )))?;
 
         // Compute where to put the new item.
         // Either way, we ensure that we insert the new item in a way such that between
@@ -450,12 +457,14 @@ pub fn new_allocation(
             // everything else off the stack, invalidating all previous pointers,
             // and in particular, *all* raw pointers.
             MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique),
-            // Static memory can be referenced by "global" pointers from `tcx`.
-            // Thus we call `static_base_ptr` such that the global pointers get the same tag
+            // Global memory can be referenced by global pointers from `tcx`.
+            // Thus we call `global_base_ptr` such that the global pointers get the same tag
             // as what we use here.
+            // `Machine` is used for extern statics, and thus must also be listed here.
+            // `Env` we list because we can get away with precise tracking there.
             // The base pointer is not unique, so the base permission is `SharedReadWrite`.
-            MemoryKind::Machine(MiriMemoryKind::Static) =>
-                (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite),
+            MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env) =>
+                (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite),
             // Everything else we handle entirely untagged for now.
             // FIXME: experiment with more precise tracking.
             _ => (Tag::Untagged, Permission::SharedReadWrite),
@@ -581,7 +590,9 @@ fn retag_reference(
             // breaking `Rc::from_raw`.
             RefKind::Raw { .. } => Tag::Untagged,
             // All other pointesr are properly tracked.
-            _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()),
+            _ => Tag::Tagged(
+                this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(),
+            ),
         };
 
         // Reborrow.
@@ -632,4 +643,3 @@ fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> {
         Ok(())
     }
 }
-