|
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