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 ;
@@ -57,7 +57,7 @@ pub(super) struct LocationState {
57
57
impl LocationState {
58
58
/// Constructs a new initial state. It has neither been accessed, nor been subjected
59
59
/// to any foreign access yet.
60
- /// The permission is not allowed to be `Active `.
60
+ /// The permission is not allowed to be `Unique `.
61
61
/// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
62
62
pub fn new_non_accessed ( permission : Permission , sifa : IdempotentForeignAccess ) -> Self {
63
63
assert ! ( permission. is_initial( ) || permission. is_disabled( ) ) ;
@@ -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 `Active` 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
}
@@ -170,7 +157,7 @@ impl LocationState {
170
157
}
171
158
if self . permission . is_frozen ( ) && access_kind == AccessKind :: Read {
172
159
// A foreign read to a `Frozen` tag will have almost no observable effect.
173
- // It's a theorem that `Frozen` nodes have no active children, so all children
160
+ // It's a theorem that `Frozen` nodes have no `Unique` children, so all children
174
161
// already survive foreign reads. Foreign reads in general have almost no
175
162
// effect, the only further thing they could do is make protected `Reserved`
176
163
// nodes become conflicted, i.e. make them reject child writes for the further
@@ -265,7 +252,7 @@ pub(super) struct Node {
265
252
pub children : SmallVec < [ UniIndex ; 4 ] > ,
266
253
/// Either `Reserved`, `Frozen`, or `Disabled`, it is the permission this tag will
267
254
/// lazily be initialized to on the first access.
268
- /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active ` by
255
+ /// It is only ever `Disabled` for a tree root, since the root is initialized to `Unique ` by
269
256
/// its own separate mechanism.
270
257
default_initial_perm : Permission ,
271
258
/// The default initial (strongest) idempotent foreign access.
@@ -598,14 +585,14 @@ impl Tree {
598
585
} ;
599
586
let rperms = {
600
587
let mut perms = UniValMap :: default ( ) ;
601
- // We manually set it to `Active ` on all in-bounds positions.
602
- // We also ensure that it is accessed, so that no `Active ` but
588
+ // We manually set it to `Unique ` on all in-bounds positions.
589
+ // We also ensure that it is accessed, so that no `Unique ` but
603
590
// not yet accessed nodes exist. Essentially, we pretend there
604
- // was a write that initialized these to `Active `.
591
+ // was a write that initialized these to `Unique `.
605
592
perms. insert (
606
593
root_idx,
607
594
LocationState :: new_accessed (
608
- Permission :: new_active ( ) ,
595
+ Permission :: new_unique ( ) ,
609
596
IdempotentForeignAccess :: None ,
610
597
) ,
611
598
) ;
@@ -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 {
@@ -790,7 +772,7 @@ impl<'tcx> Tree {
790
772
/// - the access will be applied only to accessed locations of the allocation,
791
773
/// - it will not be visible to children,
792
774
/// - it will be recorded as a `FnExit` diagnostic access
793
- /// - and it will be a read except if the location is `Active `, i.e. has been written to,
775
+ /// - and it will be a read except if the location is `Unique `, i.e. has been written to,
794
776
/// in which case it will be a write.
795
777
///
796
778
/// `LocationState::perform_access` will take care of raising transition
0 commit comments