Skip to content

Commit e146fdd

Browse files
committed
Auto merge of #118134 - Nilstrieb:rollup-kyo1l6e, r=Nilstrieb
Rollup of 6 pull requests Successful merges: - #116085 (rustdoc-search: add support for traits and associated types) - #117522 (Remove `--check-cfg` checking of command line `--cfg` args) - #118029 (Expand Miri's BorTag GC to a Provenance GC) - #118035 (Fix early param lifetimes in generic_const_exprs) - #118083 (Remove i686-apple-darwin cross-testing) - #118091 (Remove now deprecated target x86_64-sun-solaris.) r? `@ghost` `@rustbot` modify labels: rollup
2 parents e10b3c2 + e87ccba commit e146fdd

40 files changed

+424
-308
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737

3838
- name: Set the tag GC interval to 1 on linux
3939
if: runner.os == 'Linux'
40-
run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV
40+
run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV
4141

4242
# Cache the global cargo directory, but NOT the local `target` directory which
4343
# we cannot reuse anyway when the nightly changes (and it grows quite large

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,10 @@ to Miri failing to detect cases of undefined behavior in a program.
411411
without an explicit value), `none` means it never recurses, `scalar` means it only recurses for
412412
types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as
413413
individual scalars or pairs of scalars). Setting this to `none` is **unsound**.
414-
* `-Zmiri-tag-gc=<blocks>` configures how often the pointer tag garbage collector runs. The default
415-
is to search for and remove unreachable tags once every `10000` basic blocks. Setting this to
416-
`0` disables the garbage collector, which causes some programs to have explosive memory usage
417-
and/or super-linear runtime.
414+
* `-Zmiri-provenance-gc=<blocks>` configures how often the pointer provenance garbage collector runs.
415+
The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting
416+
this to `0` disables the garbage collector, which causes some programs to have explosive memory
417+
usage and/or super-linear runtime.
418418
* `-Zmiri-track-alloc-id=<id1>,<id2>,...` shows a backtrace when the given allocations are
419419
being allocated or freed. This helps in debugging memory leaks and
420420
use after free bugs. Specifying this argument multiple times does not overwrite the previous

src/bin/miri.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -531,10 +531,10 @@ fn main() {
531531
Err(err) => show_error!("-Zmiri-report-progress requires a `u32`: {}", err),
532532
};
533533
miri_config.report_progress = Some(interval);
534-
} else if let Some(param) = arg.strip_prefix("-Zmiri-tag-gc=") {
534+
} else if let Some(param) = arg.strip_prefix("-Zmiri-provenance-gc=") {
535535
let interval = match param.parse::<u32>() {
536536
Ok(i) => i,
537-
Err(err) => show_error!("-Zmiri-tag-gc requires a `u32`: {}", err),
537+
Err(err) => show_error!("-Zmiri-provenance-gc requires a `u32`: {}", err),
538538
};
539539
miri_config.gc_interval = interval;
540540
} else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") {

src/borrow_tracker/mod.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ pub struct FrameState {
7575
protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
7676
}
7777

78-
impl VisitTags for FrameState {
79-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
78+
impl VisitProvenance for FrameState {
79+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
8080
// `protected_tags` are already recorded by `GlobalStateInner`.
8181
}
8282
}
@@ -110,10 +110,10 @@ pub struct GlobalStateInner {
110110
unique_is_unique: bool,
111111
}
112112

113-
impl VisitTags for GlobalStateInner {
114-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
113+
impl VisitProvenance for GlobalStateInner {
114+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
115115
for &tag in self.protected_tags.keys() {
116-
visit(tag);
116+
visit(None, Some(tag));
117117
}
118118
// The only other candidate is base_ptr_tags, and that does not need visiting since we don't ever
119119
// GC the bottommost/root tag.
@@ -236,6 +236,10 @@ impl GlobalStateInner {
236236
tag
237237
})
238238
}
239+
240+
pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) {
241+
self.base_ptr_tags.retain(|id, _| allocs.is_live(*id));
242+
}
239243
}
240244

241245
/// Which borrow tracking method to use
@@ -503,11 +507,11 @@ impl AllocState {
503507
}
504508
}
505509

506-
impl VisitTags for AllocState {
507-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
510+
impl VisitProvenance for AllocState {
511+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
508512
match self {
509-
AllocState::StackedBorrows(sb) => sb.visit_tags(visit),
510-
AllocState::TreeBorrows(tb) => tb.visit_tags(visit),
513+
AllocState::StackedBorrows(sb) => sb.visit_provenance(visit),
514+
AllocState::TreeBorrows(tb) => tb.visit_provenance(visit),
511515
}
512516
}
513517
}

src/borrow_tracker/stacked_borrows/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,10 @@ impl Stacks {
462462
}
463463
}
464464

465-
impl VisitTags for Stacks {
466-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
465+
impl VisitProvenance for Stacks {
466+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
467467
for tag in self.exposed_tags.iter().copied() {
468-
visit(tag);
468+
visit(None, Some(tag));
469469
}
470470
}
471471
}

src/borrow_tracker/tree_borrows/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ impl<'tcx> Tree {
200200
/// Climb the tree to get the tag of a distant ancestor.
201201
/// Allows operations on tags that are unreachable by the program
202202
/// but still exist in the tree. Not guaranteed to perform consistently
203-
/// if `tag-gc=1`.
203+
/// if `provenance-gc=1`.
204204
fn nth_parent(&self, tag: BorTag, nth_parent: u8) -> Option<BorTag> {
205205
let mut idx = self.tag_mapping.get(&tag).unwrap();
206206
for _ in 0..nth_parent {

src/borrow_tracker/tree_borrows/tree.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -742,11 +742,11 @@ impl Tree {
742742
}
743743
}
744744

745-
impl VisitTags for Tree {
746-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
745+
impl VisitProvenance for Tree {
746+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
747747
// To ensure that the root never gets removed, we visit it
748748
// (the `root` node of `Tree` is not an `Option<_>`)
749-
visit(self.nodes.get(self.root).unwrap().tag)
749+
visit(None, Some(self.nodes.get(self.root).unwrap().tag))
750750
}
751751
}
752752

src/concurrency/data_race.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -790,9 +790,9 @@ pub struct VClockAlloc {
790790
alloc_ranges: RefCell<RangeMap<MemoryCellClocks>>,
791791
}
792792

793-
impl VisitTags for VClockAlloc {
794-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
795-
// No tags here.
793+
impl VisitProvenance for VClockAlloc {
794+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
795+
// No tags or allocIds here.
796796
}
797797
}
798798

@@ -1404,8 +1404,8 @@ pub struct GlobalState {
14041404
pub track_outdated_loads: bool,
14051405
}
14061406

1407-
impl VisitTags for GlobalState {
1408-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
1407+
impl VisitProvenance for GlobalState {
1408+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
14091409
// We don't have any tags.
14101410
}
14111411
}

src/concurrency/init_once.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ pub(super) struct InitOnce<'mir, 'tcx> {
4545
data_race: VClock,
4646
}
4747

48-
impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> {
49-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
48+
impl<'mir, 'tcx> VisitProvenance for InitOnce<'mir, 'tcx> {
49+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
5050
for waiter in self.waiters.iter() {
51-
waiter.callback.visit_tags(visit);
51+
waiter.callback.visit_provenance(visit);
5252
}
5353
}
5454
}

src/concurrency/sync.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ pub(crate) struct SynchronizationState<'mir, 'tcx> {
181181
pub(super) init_onces: IndexVec<InitOnceId, InitOnce<'mir, 'tcx>>,
182182
}
183183

184-
impl<'mir, 'tcx> VisitTags for SynchronizationState<'mir, 'tcx> {
185-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
184+
impl<'mir, 'tcx> VisitProvenance for SynchronizationState<'mir, 'tcx> {
185+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
186186
for init_once in self.init_onces.iter() {
187-
init_once.visit_tags(visit);
187+
init_once.visit_provenance(visit);
188188
}
189189
}
190190
}

src/concurrency/thread.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub enum TlsAllocAction {
4343
}
4444

4545
/// Trait for callbacks that can be executed when some event happens, such as after a timeout.
46-
pub trait MachineCallback<'mir, 'tcx>: VisitTags {
46+
pub trait MachineCallback<'mir, 'tcx>: VisitProvenance {
4747
fn call(&self, ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx>;
4848
}
4949

@@ -228,8 +228,8 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
228228
}
229229
}
230230

231-
impl VisitTags for Thread<'_, '_> {
232-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
231+
impl VisitProvenance for Thread<'_, '_> {
232+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
233233
let Thread {
234234
panic_payloads: panic_payload,
235235
last_error,
@@ -242,17 +242,17 @@ impl VisitTags for Thread<'_, '_> {
242242
} = self;
243243

244244
for payload in panic_payload {
245-
payload.visit_tags(visit);
245+
payload.visit_provenance(visit);
246246
}
247-
last_error.visit_tags(visit);
247+
last_error.visit_provenance(visit);
248248
for frame in stack {
249-
frame.visit_tags(visit)
249+
frame.visit_provenance(visit)
250250
}
251251
}
252252
}
253253

254-
impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> {
255-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
254+
impl VisitProvenance for Frame<'_, '_, Provenance, FrameExtra<'_>> {
255+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
256256
let Frame {
257257
return_place,
258258
locals,
@@ -266,22 +266,22 @@ impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> {
266266
} = self;
267267

268268
// Return place.
269-
return_place.visit_tags(visit);
269+
return_place.visit_provenance(visit);
270270
// Locals.
271271
for local in locals.iter() {
272272
match local.as_mplace_or_imm() {
273273
None => {}
274274
Some(Either::Left((ptr, meta))) => {
275-
ptr.visit_tags(visit);
276-
meta.visit_tags(visit);
275+
ptr.visit_provenance(visit);
276+
meta.visit_provenance(visit);
277277
}
278278
Some(Either::Right(imm)) => {
279-
imm.visit_tags(visit);
279+
imm.visit_provenance(visit);
280280
}
281281
}
282282
}
283283

284-
extra.visit_tags(visit);
284+
extra.visit_provenance(visit);
285285
}
286286
}
287287

@@ -341,8 +341,8 @@ pub struct ThreadManager<'mir, 'tcx> {
341341
timeout_callbacks: FxHashMap<ThreadId, TimeoutCallbackInfo<'mir, 'tcx>>,
342342
}
343343

344-
impl VisitTags for ThreadManager<'_, '_> {
345-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
344+
impl VisitProvenance for ThreadManager<'_, '_> {
345+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
346346
let ThreadManager {
347347
threads,
348348
thread_local_alloc_ids,
@@ -353,15 +353,15 @@ impl VisitTags for ThreadManager<'_, '_> {
353353
} = self;
354354

355355
for thread in threads {
356-
thread.visit_tags(visit);
356+
thread.visit_provenance(visit);
357357
}
358358
for ptr in thread_local_alloc_ids.borrow().values() {
359-
ptr.visit_tags(visit);
359+
ptr.visit_provenance(visit);
360360
}
361361
for callback in timeout_callbacks.values() {
362-
callback.callback.visit_tags(visit);
362+
callback.callback.visit_provenance(visit);
363363
}
364-
sync.visit_tags(visit);
364+
sync.visit_provenance(visit);
365365
}
366366
}
367367

src/concurrency/weak_memory.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,15 @@ pub struct StoreBufferAlloc {
108108
store_buffers: RefCell<RangeObjectMap<StoreBuffer>>,
109109
}
110110

111-
impl VisitTags for StoreBufferAlloc {
112-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
111+
impl VisitProvenance for StoreBufferAlloc {
112+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
113113
let Self { store_buffers } = self;
114114
for val in store_buffers
115115
.borrow()
116116
.iter()
117117
.flat_map(|buf| buf.buffer.iter().map(|element| &element.val))
118118
{
119-
val.visit_tags(visit);
119+
val.visit_provenance(visit);
120120
}
121121
}
122122
}

src/intptrcast.rs

+35-10
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,21 @@ pub struct GlobalStateInner {
4646
provenance_mode: ProvenanceMode,
4747
}
4848

49-
impl VisitTags for GlobalStateInner {
50-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
51-
// Nothing to visit here.
49+
impl VisitProvenance for GlobalStateInner {
50+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
51+
let GlobalStateInner {
52+
int_to_ptr_map: _,
53+
base_addr: _,
54+
exposed: _,
55+
next_base_addr: _,
56+
provenance_mode: _,
57+
} = self;
58+
// Though base_addr, int_to_ptr_map, and exposed contain AllocIds, we do not want to visit them.
59+
// int_to_ptr_map and exposed must contain only live allocations, and those
60+
// are never garbage collected.
61+
// base_addr is only relevant if we have a pointer to an AllocId and need to look up its
62+
// base address; so if an AllocId is not reachable from somewhere else we can remove it
63+
// here.
5264
}
5365
}
5466

@@ -62,6 +74,12 @@ impl GlobalStateInner {
6274
provenance_mode: config.provenance_mode,
6375
}
6476
}
77+
78+
pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) {
79+
// `exposed` and `int_to_ptr_map` are cleared immediately when an allocation
80+
// 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));
82+
}
6583
}
6684

6785
/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
@@ -107,7 +125,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
107125
// We only use this provenance if it has been exposed.
108126
if global_state.exposed.contains(&alloc_id) {
109127
// This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed.
110-
debug_assert!(!matches!(ecx.get_alloc_info(alloc_id).2, AllocKind::Dead));
128+
debug_assert!(ecx.is_alloc_live(alloc_id));
111129
Some(alloc_id)
112130
} else {
113131
None
@@ -181,12 +199,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
181199
let ecx = self.eval_context_mut();
182200
let global_state = ecx.machine.intptrcast.get_mut();
183201
// In strict mode, we don't need this, so we can save some cycles by not tracking it.
184-
if global_state.provenance_mode != ProvenanceMode::Strict {
185-
trace!("Exposing allocation id {alloc_id:?}");
186-
global_state.exposed.insert(alloc_id);
187-
if ecx.machine.borrow_tracker.is_some() {
188-
ecx.expose_tag(alloc_id, tag)?;
189-
}
202+
if global_state.provenance_mode == ProvenanceMode::Strict {
203+
return Ok(());
204+
}
205+
// Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation
206+
// via int2ptr.
207+
if !ecx.is_alloc_live(alloc_id) {
208+
return Ok(());
209+
}
210+
trace!("Exposing allocation id {alloc_id:?}");
211+
let global_state = ecx.machine.intptrcast.get_mut();
212+
global_state.exposed.insert(alloc_id);
213+
if ecx.machine.borrow_tracker.is_some() {
214+
ecx.expose_tag(alloc_id, tag)?;
190215
}
191216
Ok(())
192217
}

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ mod intptrcast;
7777
mod machine;
7878
mod mono_hash_map;
7979
mod operator;
80+
mod provenance_gc;
8081
mod range_map;
8182
mod shims;
82-
mod tag_gc;
8383

8484
// Establish a "crate-wide prelude": we often import `crate::*`.
8585

@@ -125,8 +125,8 @@ pub use crate::machine::{
125125
};
126126
pub use crate::mono_hash_map::MonoHashMap;
127127
pub use crate::operator::EvalContextExt as _;
128+
pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs};
128129
pub use crate::range_map::RangeMap;
129-
pub use crate::tag_gc::{EvalContextExt as _, VisitTags};
130130

131131
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
132132
/// set per default, for maximal validation power.

0 commit comments

Comments
 (0)