Skip to content

Commit 17bdf20

Browse files
committed
Miri: Skip over GlobalAllocs when GC'ing base_addr
1 parent d7661d5 commit 17bdf20

File tree

5 files changed

+65
-59
lines changed

5 files changed

+65
-59
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
5858
}
5959

6060
/// The return value of `get_alloc_info` indicates the "kind" of the allocation.
61+
#[derive(Clone, Copy)]
6162
pub enum AllocKind {
6263
/// A regular live data allocation.
6364
LiveData,
65+
/// A regular live data allocation that will never be deallocated.
66+
GlobalLiveData,
6467
/// A function allocation (that fn ptrs point to).
6568
Function,
6669
/// A (symbolic) vtable allocation.
@@ -69,6 +72,24 @@ pub enum AllocKind {
6972
Dead,
7073
}
7174

75+
impl AllocKind {
76+
pub fn is_global(self) -> bool {
77+
use AllocKind::*;
78+
match self {
79+
GlobalLiveData | Function | VTable => true,
80+
LiveData | Dead => false,
81+
}
82+
}
83+
84+
pub fn is_live_data(self) -> bool {
85+
use AllocKind::*;
86+
match self {
87+
GlobalLiveData | LiveData => true,
88+
Function | VTable | Dead => false,
89+
}
90+
}
91+
}
92+
7293
/// The value of a function pointer.
7394
#[derive(Debug, Copy, Clone)]
7495
pub enum FnVal<'tcx, Other> {
@@ -733,13 +754,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
733754
.expect("statics should not have generic parameters");
734755
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
735756
assert!(layout.is_sized());
736-
(layout.size, layout.align.abi, AllocKind::LiveData)
757+
(layout.size, layout.align.abi, AllocKind::GlobalLiveData)
737758
}
738759
Some(GlobalAlloc::Memory(alloc)) => {
739760
// Need to duplicate the logic here, because the global allocations have
740761
// different associated types than the interpreter-local ones.
741762
let alloc = alloc.inner();
742-
(alloc.size(), alloc.align, AllocKind::LiveData)
763+
(alloc.size(), alloc.align, AllocKind::GlobalLiveData)
743764
}
744765
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
745766
Some(GlobalAlloc::VTable(..)) => {

src/tools/miri/src/borrow_tracker/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
382382
// pointer is readable, and the implicit read access inserted
383383
// will never cause UB on the pointer itself.
384384
let (_, _, kind) = this.get_alloc_info(*alloc_id);
385-
if matches!(kind, AllocKind::LiveData) {
385+
if kind.is_live_data() {
386386
let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap();
387387
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
388388
alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

+28-38
Original file line numberDiff line numberDiff line change
@@ -648,32 +648,27 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
648648
};
649649

650650
let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
651-
match alloc_kind {
652-
AllocKind::LiveData => {
653-
// This should have alloc_extra data, but `get_alloc_extra` can still fail
654-
// if converting this alloc_id from a global to a local one
655-
// uncovers a non-supported `extern static`.
656-
let extra = this.get_alloc_extra(alloc_id)?;
657-
let mut stacked_borrows = extra
658-
.borrow_tracker_sb()
659-
.borrow_mut();
660-
// Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag.
661-
// FIXME: can this be done cleaner?
662-
let dcx = DiagnosticCxBuilder::retag(
663-
&this.machine,
664-
retag_info,
665-
new_tag,
666-
orig_tag,
667-
alloc_range(base_offset, size),
668-
);
669-
let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
670-
dcx.log_creation();
671-
if new_perm.protector().is_some() {
672-
dcx.log_protector();
673-
}
674-
},
675-
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
676-
// No stacked borrows on these allocations.
651+
if alloc_kind.is_live_data() {
652+
// This should have alloc_extra data, but `get_alloc_extra` can still fail
653+
// if converting this alloc_id from a global to a local one
654+
// uncovers a non-supported `extern static`.
655+
let extra = this.get_alloc_extra(alloc_id)?;
656+
let mut stacked_borrows = extra
657+
.borrow_tracker_sb()
658+
.borrow_mut();
659+
// Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag.
660+
// FIXME: can this be done cleaner?
661+
let dcx = DiagnosticCxBuilder::retag(
662+
&this.machine,
663+
retag_info,
664+
new_tag,
665+
orig_tag,
666+
alloc_range(base_offset, size),
667+
);
668+
let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
669+
dcx.log_creation();
670+
if new_perm.protector().is_some() {
671+
dcx.log_protector();
677672
}
678673
}
679674
Ok(())
@@ -1012,18 +1007,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10121007
// This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
10131008
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
10141009
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
1015-
match kind {
1016-
AllocKind::LiveData => {
1017-
// This should have alloc_extra data, but `get_alloc_extra` can still fail
1018-
// if converting this alloc_id from a global to a local one
1019-
// uncovers a non-supported `extern static`.
1020-
let alloc_extra = this.get_alloc_extra(alloc_id)?;
1021-
trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
1022-
alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag);
1023-
}
1024-
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
1025-
// No stacked borrows on these allocations.
1026-
}
1010+
if kind.is_live_data() {
1011+
// This should have alloc_extra data, but `get_alloc_extra` can still fail
1012+
// if converting this alloc_id from a global to a local one
1013+
// uncovers a non-supported `extern static`.
1014+
let alloc_extra = this.get_alloc_extra(alloc_id)?;
1015+
trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
1016+
alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag);
10271017
}
10281018
Ok(())
10291019
}

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
285285
}
286286

287287
let alloc_kind = this.get_alloc_info(alloc_id).2;
288-
if !matches!(alloc_kind, AllocKind::LiveData) {
288+
if !alloc_kind.is_live_data() {
289289
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
290290
// There's not actually any bytes here where accesses could even be tracked.
291291
// Just produce the new provenance, nothing else to do.
@@ -538,18 +538,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
538538
// This is okay because accessing them is UB anyway, no need for any Tree Borrows checks.
539539
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
540540
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
541-
match kind {
542-
AllocKind::LiveData => {
543-
// This should have alloc_extra data, but `get_alloc_extra` can still fail
544-
// if converting this alloc_id from a global to a local one
545-
// uncovers a non-supported `extern static`.
546-
let alloc_extra = this.get_alloc_extra(alloc_id)?;
547-
trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}");
548-
alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag);
549-
}
550-
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
551-
// No tree borrows on these allocations.
552-
}
541+
if kind.is_live_data() {
542+
// This should have alloc_extra data, but `get_alloc_extra` can still fail
543+
// if converting this alloc_id from a global to a local one
544+
// uncovers a non-supported `extern static`.
545+
let alloc_extra = this.get_alloc_extra(alloc_id)?;
546+
trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}");
547+
alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag);
553548
}
554549
Ok(())
555550
}

src/tools/miri/src/intptrcast.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct GlobalStateInner {
3535
/// `AllocExtra` because function pointers also have a base address, and
3636
/// they do not have an `AllocExtra`.
3737
/// This is the inverse of `int_to_ptr_map`.
38-
base_addr: FxHashMap<AllocId, u64>,
38+
base_addr: FxHashMap<AllocId, (u64, bool)>,
3939
/// Whether an allocation has been exposed or not. This cannot be put
4040
/// into `AllocExtra` for the same reason as `base_addr`.
4141
exposed: FxHashSet<AllocId>,
@@ -78,7 +78,7 @@ impl GlobalStateInner {
7878
pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) {
7979
// `exposed` and `int_to_ptr_map` are cleared immediately when an allocation
8080
// is freed, so `base_addr` is the only one we have to clean up based on the GC.
81-
self.base_addr.retain(|id, _| allocs.is_live(*id));
81+
self.base_addr.retain(|id, (_addr, is_global)| *is_global || allocs.is_live(*id));
8282
}
8383
}
8484

@@ -138,7 +138,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
138138
let global_state = &mut *global_state;
139139

140140
Ok(match global_state.base_addr.entry(alloc_id) {
141-
Entry::Occupied(entry) => *entry.get(),
141+
Entry::Occupied(entry) => entry.get().0,
142142
Entry::Vacant(entry) => {
143143
let (size, align, kind) = ecx.get_alloc_info(alloc_id);
144144
// This is either called immediately after allocation (and then cached), or when
@@ -161,7 +161,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
161161
.checked_add(slack)
162162
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
163163
let base_addr = align_addr(base_addr, align.bytes());
164-
entry.insert(base_addr);
164+
entry.insert((base_addr, kind.is_global()));
165165
trace!(
166166
"Assigning base address {:#x} to allocation {:?} (size: {}, align: {}, slack: {})",
167167
base_addr,
@@ -312,7 +312,7 @@ impl GlobalStateInner {
312312
// returns a dead allocation.
313313
// To avoid a linear scan we first look up the address in `base_addr`, and then find it in
314314
// `int_to_ptr_map`.
315-
let addr = *self.base_addr.get(&dead_id).unwrap();
315+
let addr = self.base_addr.get(&dead_id).unwrap().0;
316316
let pos = self.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap();
317317
let removed = self.int_to_ptr_map.remove(pos);
318318
assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing

0 commit comments

Comments
 (0)