|
11 | 11 | //! - idempotency properties asserted in `perms.rs` (for optimizations)
|
12 | 12 |
|
13 | 13 | use std::ops::Range;
|
14 |
| -use std::{fmt, mem}; |
| 14 | +use std::{cmp, fmt, mem}; |
15 | 15 |
|
16 | 16 | use rustc_abi::Size;
|
17 | 17 | use rustc_data_structures::fx::FxHashSet;
|
@@ -73,23 +73,10 @@ impl LocationState {
|
73 | 73 |
|
74 | 74 | /// Check if the location has been accessed, i.e. if it has
|
75 | 75 | /// ever been accessed through a child pointer.
|
76 |
| - pub fn is_accessed(&self) -> bool { |
| 76 | + pub fn accessed(&self) -> bool { |
77 | 77 | self.accessed
|
78 | 78 | }
|
79 | 79 |
|
80 |
| - /// Check if the state can exist as the initial permission of a pointer. |
81 |
| - /// |
82 |
| - /// Do not confuse with `is_accessed`, the two are almost orthogonal |
83 |
| - /// as apart from `Unique` which is not initial and must be accessed, |
84 |
| - /// any other permission can have an arbitrary combination of being |
85 |
| - /// initial/accessed. |
86 |
| - /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally |
87 |
| - /// passes and can be uncommented, remove this `#[allow(dead_code)]`. |
88 |
| - #[cfg_attr(not(test), allow(dead_code))] |
89 |
| - pub fn is_initial(&self) -> bool { |
90 |
| - self.permission.is_initial() |
91 |
| - } |
92 |
| - |
93 | 80 | pub fn permission(&self) -> Permission {
|
94 | 81 | self.permission
|
95 | 82 | }
|
@@ -618,67 +605,62 @@ impl Tree {
|
618 | 605 | impl<'tcx> Tree {
|
619 | 606 | /// Insert a new tag in the tree.
|
620 | 607 | ///
|
621 |
| - /// `initial_perms` defines the initial permissions for the part of memory |
622 |
| - /// that is already considered "initialized" immediately. The ranges in this |
623 |
| - /// map are relative to `base_offset`. |
624 |
| - /// `default_perm` defines the initial permission for the rest of the allocation. |
625 |
| - /// |
626 |
| - /// For all non-accessed locations in the RangeMap (those that haven't had an |
627 |
| - /// implicit read), their SIFA must be weaker than or as weak as the SIFA of |
628 |
| - /// `default_perm`. |
| 608 | + /// `inside_perm` defines the initial permissions for a block of memory starting at |
| 609 | + /// `base_offset`. These may nor may not be already marked as "accessed". |
| 610 | + /// `outside_perm` defines the initial permission for the rest of the allocation. |
| 611 | + /// These are definitely not "accessed". |
629 | 612 | pub(super) fn new_child(
|
630 | 613 | &mut self,
|
631 | 614 | base_offset: Size,
|
632 | 615 | parent_tag: BorTag,
|
633 | 616 | new_tag: BorTag,
|
634 |
| - initial_perms: DedupRangeMap<LocationState>, |
635 |
| - default_perm: Permission, |
| 617 | + inside_perms: DedupRangeMap<LocationState>, |
| 618 | + outside_perm: Permission, |
636 | 619 | protected: bool,
|
637 | 620 | span: Span,
|
638 | 621 | ) -> InterpResult<'tcx> {
|
639 | 622 | let idx = self.tag_mapping.insert(new_tag);
|
640 | 623 | let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
|
641 |
| - assert!(default_perm.is_initial()); |
| 624 | + assert!(outside_perm.is_initial()); |
642 | 625 |
|
643 | 626 | let default_strongest_idempotent =
|
644 |
| - default_perm.strongest_idempotent_foreign_access(protected); |
| 627 | + outside_perm.strongest_idempotent_foreign_access(protected); |
645 | 628 | // Create the node
|
646 | 629 | self.nodes.insert(
|
647 | 630 | idx,
|
648 | 631 | Node {
|
649 | 632 | tag: new_tag,
|
650 | 633 | parent: Some(parent_idx),
|
651 | 634 | children: SmallVec::default(),
|
652 |
| - default_initial_perm: default_perm, |
| 635 | + default_initial_perm: outside_perm, |
653 | 636 | default_initial_idempotent_foreign_access: default_strongest_idempotent,
|
654 |
| - debug_info: NodeDebugInfo::new(new_tag, default_perm, span), |
| 637 | + debug_info: NodeDebugInfo::new(new_tag, outside_perm, span), |
655 | 638 | },
|
656 | 639 | );
|
657 | 640 | // Register new_tag as a child of parent_tag
|
658 | 641 | self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
|
659 | 642 |
|
| 643 | + // We need to know the biggest SIFA for `update_last_accessed_after_retag` below. |
| 644 | + let mut max_sifa = default_strongest_idempotent; |
660 | 645 | for (Range { start, end }, &perm) in
|
661 |
| - initial_perms.iter(Size::from_bytes(0), initial_perms.size()) |
| 646 | + inside_perms.iter(Size::from_bytes(0), inside_perms.size()) |
662 | 647 | {
|
663 |
| - assert!(perm.is_initial()); |
| 648 | + assert!(perm.permission.is_initial()); |
| 649 | + max_sifa = cmp::max(max_sifa, perm.idempotent_foreign_access); |
664 | 650 | for (_perms_range, perms) in self
|
665 | 651 | .rperms
|
666 | 652 | .iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start))
|
667 | 653 | {
|
668 |
| - assert!( |
669 |
| - default_strongest_idempotent |
670 |
| - >= perm.permission.strongest_idempotent_foreign_access(protected) |
671 |
| - ); |
672 | 654 | perms.insert(idx, perm);
|
673 | 655 | }
|
674 | 656 | }
|
675 | 657 |
|
676 |
| - // Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`). |
677 |
| - // We now weaken the recorded SIFA for our parents, until the invariant is restored. |
678 |
| - // We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA |
679 |
| - // for the new permission statically, and use that. |
680 |
| - // See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm`. |
681 |
| - self.update_last_accessed_after_retag(parent_idx, default_strongest_idempotent); |
| 658 | + // Inserting the new perms might have broken the SIFA invariant (see |
| 659 | + // `foreign_access_skipping.rs`). We now weaken the recorded SIFA for our parents, until the |
| 660 | + // invariant is restored. We could weaken them all to `LocalAccess`, but it is more |
| 661 | + // efficient to compute the SIFA for the new permission statically, and use that. For this |
| 662 | + // we need the *maximum* SIFA (`Write` needs more fixup than `None`). |
| 663 | + self.update_last_accessed_after_retag(parent_idx, max_sifa); |
682 | 664 |
|
683 | 665 | interp_ok(())
|
684 | 666 | }
|
@@ -755,9 +737,9 @@ impl<'tcx> Tree {
|
755 | 737 | == Some(&ProtectorKind::StrongProtector)
|
756 | 738 | // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
|
757 | 739 | // Related to https://github.com/rust-lang/rust/issues/55005.
|
758 |
| - && !perm.permission().is_cell() |
| 740 | + && !perm.permission.is_cell() |
759 | 741 | // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
|
760 |
| - && perm.is_accessed() |
| 742 | + && perm.accessed |
761 | 743 | {
|
762 | 744 | Err(TransitionError::ProtectedDealloc)
|
763 | 745 | } else {
|
|
0 commit comments