Skip to content

Commit 279c9ba

Browse files
committed
Auto merge of #121936 - RalfJung:miri, r=RalfJung
Miri subtree update r? `@ghost`
2 parents 2690737 + 639fab7 commit 279c9ba

File tree

196 files changed

+607
-343
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

196 files changed

+607
-343
lines changed

src/tools/miri/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ to Miri failing to detect cases of undefined behavior in a program.
412412
The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting
413413
this to `0` disables the garbage collector, which causes some programs to have explosive memory
414414
usage and/or super-linear runtime.
415+
* `-Zmiri-track-alloc-accesses` show not only allocation and free events for tracked allocations,
416+
but also reads and writes.
415417
* `-Zmiri-track-alloc-id=<id1>,<id2>,...` shows a backtrace when the given allocations are
416418
being allocated or freed. This helps in debugging memory leaks and
417419
use after free bugs. Specifying this argument multiple times does not overwrite the previous
@@ -588,6 +590,7 @@ Definite bugs found:
588590
* [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084)
589591
* [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460)
590592
* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138)
593+
* [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084))
591594

592595
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
593596

src/tools/miri/miri-script/src/commands.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,17 @@ impl Command {
356356
.unwrap_or_else(|_| "0".into())
357357
.parse()
358358
.context("failed to parse MIRI_SEED_START")?;
359-
let seed_count: u64 = env::var("MIRI_SEEDS")
360-
.unwrap_or_else(|_| "256".into())
361-
.parse()
362-
.context("failed to parse MIRI_SEEDS")?;
363-
let seed_end = seed_start + seed_count;
359+
let seed_end: u64 = match (env::var("MIRI_SEEDS"), env::var("MIRI_SEED_END")) {
360+
(Ok(_), Ok(_)) => bail!("Only one of MIRI_SEEDS and MIRI_SEED_END may be set"),
361+
(Ok(seeds), Err(_)) =>
362+
seed_start + seeds.parse::<u64>().context("failed to parse MIRI_SEEDS")?,
363+
(Err(_), Ok(seed_end)) => seed_end.parse().context("failed to parse MIRI_SEED_END")?,
364+
(Err(_), Err(_)) => seed_start + 256,
365+
};
366+
if seed_end <= seed_start {
367+
bail!("the end of the seed range must be larger than the start.");
368+
}
369+
364370
let Some((command_name, trailing_args)) = command.split_first() else {
365371
bail!("expected many-seeds command to be non-empty");
366372
};

src/tools/miri/miri-script/src/main.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ sysroot, to prevent conflicts with other toolchains.
113113
./miri many-seeds <command>:
114114
Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
115115
variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
116-
many different seeds. The MIRI_SEEDS variable controls how many seeds are being
117-
tried; MIRI_SEED_START controls the first seed to try.
116+
many different seeds. MIRI_SEED_START controls the first seed to try (default: 0).
117+
MIRI_SEEDS controls how many seeds are being tried (default: 256);
118+
alternatively, MIRI_SEED_END controls the end of the (exclusive) seed range to try.
118119
119120
./miri bench <benches>:
120121
Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.

src/tools/miri/miri.bat

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
:: Windows will not execute the bash script, and select this.
33
@echo off
44
set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
5-
cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml
5+
6+
:: If any other steps are added, the "|| exit /b" must be appended to early
7+
:: return from the script. If not, it will continue execution.
8+
cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml || exit /b
69

710
:: Forwards all arguments to this file to the executable.
811
:: We invoke the binary directly to avoid going through rustup, which would set some extra

src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
c5f69bdd5173a948e0131f934fa7c4cbf5e0b55f
1+
1a1876c9790f168fb51afa335a7ba3e6fc267d75

src/tools/miri/src/bin/miri.rs

+2
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ fn main() {
534534
),
535535
};
536536
miri_config.tracked_alloc_ids.extend(ids);
537+
} else if arg == "-Zmiri-track-alloc-accesses" {
538+
miri_config.track_alloc_accesses = true;
537539
} else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") {
538540
let rate = match param.parse::<f64>() {
539541
Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate,

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,6 @@ impl VisitProvenance for GlobalStateInner {
122122
/// We need interior mutable access to the global state.
123123
pub type GlobalState = RefCell<GlobalStateInner>;
124124

125-
/// Indicates which kind of access is being performed.
126-
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
127-
pub enum AccessKind {
128-
Read,
129-
Write,
130-
}
131-
132125
impl fmt::Display for AccessKind {
133126
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134127
match self {
@@ -384,7 +377,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
384377
if matches!(kind, AllocKind::LiveData) {
385378
let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static`
386379
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
387-
alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;
380+
alloc_borrow_tracker.release_protector(
381+
&this.machine,
382+
borrow_tracker,
383+
*tag,
384+
*alloc_id,
385+
)?;
388386
}
389387
}
390388
borrow_tracker.borrow_mut().end_call(&frame.extra);
@@ -498,10 +496,12 @@ impl AllocState {
498496
machine: &MiriMachine<'_, 'tcx>,
499497
global: &GlobalState,
500498
tag: BorTag,
499+
alloc_id: AllocId, // diagnostics
501500
) -> InterpResult<'tcx> {
502501
match self {
503502
AllocState::StackedBorrows(_sb) => Ok(()),
504-
AllocState::TreeBorrows(tb) => tb.borrow_mut().release_protector(machine, global, tag),
503+
AllocState::TreeBorrows(tb) =>
504+
tb.borrow_mut().release_protector(machine, global, tag, alloc_id),
505505
}
506506
}
507507
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashSet;
55
use rustc_span::{Span, SpanData};
66
use rustc_target::abi::Size;
77

8-
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind};
8+
use crate::borrow_tracker::{GlobalStateInner, ProtectorKind};
99
use crate::*;
1010

1111
/// Error reporting

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_target::abi::{Abi, Size};
1616

1717
use crate::borrow_tracker::{
1818
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
19-
AccessKind, GlobalStateInner, ProtectorKind,
19+
GlobalStateInner, ProtectorKind,
2020
};
2121
use crate::*;
2222

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::borrow_tracker::tree_borrows::{
99
tree::LocationState,
1010
unimap::UniIndex,
1111
};
12-
use crate::borrow_tracker::{AccessKind, ProtectorKind};
12+
use crate::borrow_tracker::ProtectorKind;
1313
use crate::*;
1414

1515
/// Cause of an access: either a real access or one
@@ -278,6 +278,8 @@ impl History {
278278
pub(super) struct TbError<'node> {
279279
/// What failure occurred.
280280
pub error_kind: TransitionError,
281+
/// The allocation in which the error is happening.
282+
pub alloc_id: AllocId,
281283
/// The offset (into the allocation) at which the conflict occurred.
282284
pub error_offset: u64,
283285
/// The tag on which the error was triggered.
@@ -300,7 +302,11 @@ impl TbError<'_> {
300302
let accessed = self.accessed_info;
301303
let conflicting = self.conflicting_info;
302304
let accessed_is_conflicting = accessed.tag == conflicting.tag;
303-
let title = format!("{cause} through {accessed} is forbidden");
305+
let title = format!(
306+
"{cause} through {accessed} at {alloc_id:?}[{offset:#x}] is forbidden",
307+
alloc_id = self.alloc_id,
308+
offset = self.error_offset
309+
);
304310
let (title, details, conflicting_tag_name) = match self.error_kind {
305311
ChildAccessForbidden(perm) => {
306312
let conflicting_tag_name =

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

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
use rustc_target::abi::{Abi, Size};
2-
3-
use crate::borrow_tracker::{AccessKind, GlobalState, GlobalStateInner, ProtectorKind};
41
use rustc_middle::{
52
mir::{Mutability, RetagKind},
63
ty::{
@@ -10,7 +7,9 @@ use rustc_middle::{
107
},
118
};
129
use rustc_span::def_id::DefId;
10+
use rustc_target::abi::{Abi, Size};
1311

12+
use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
1413
use crate::*;
1514

1615
pub mod diagnostics;
@@ -70,6 +69,7 @@ impl<'tcx> Tree {
7069
tag,
7170
Some(range),
7271
global,
72+
alloc_id,
7373
span,
7474
diagnostics::AccessCause::Explicit(access_kind),
7575
)
@@ -78,7 +78,7 @@ impl<'tcx> Tree {
7878
/// Check that this pointer has permission to deallocate this range.
7979
pub fn before_memory_deallocation(
8080
&mut self,
81-
_alloc_id: AllocId,
81+
alloc_id: AllocId,
8282
prov: ProvenanceExtra,
8383
range: AllocRange,
8484
machine: &MiriMachine<'_, 'tcx>,
@@ -91,7 +91,7 @@ impl<'tcx> Tree {
9191
};
9292
let global = machine.borrow_tracker.as_ref().unwrap();
9393
let span = machine.current_span();
94-
self.dealloc(tag, range, global, span)
94+
self.dealloc(tag, range, global, alloc_id, span)
9595
}
9696

9797
pub fn expose_tag(&mut self, _tag: BorTag) {
@@ -109,13 +109,15 @@ impl<'tcx> Tree {
109109
machine: &MiriMachine<'_, 'tcx>,
110110
global: &GlobalState,
111111
tag: BorTag,
112+
alloc_id: AllocId, // diagnostics
112113
) -> InterpResult<'tcx> {
113114
let span = machine.current_span();
114115
self.perform_access(
115116
AccessKind::Read,
116117
tag,
117118
None, // no specified range because it occurs on the entire allocation
118119
global,
120+
alloc_id,
119121
span,
120122
diagnostics::AccessCause::FnExit,
121123
)
@@ -211,7 +213,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
211213
let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
212214
let ty = place.layout.ty;
213215
if global.tracked_pointer_tags.contains(&new_tag) {
214-
let kind_str = format!("{new_perm:?} (pointee type {ty})");
216+
let kind_str = format!("initial state {} (pointee type {ty})", new_perm.initial_state);
215217
this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
216218
new_tag.inner(),
217219
Some(kind_str),
@@ -299,6 +301,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
299301
orig_tag,
300302
Some(range),
301303
this.machine.borrow_tracker.as_ref().unwrap(),
304+
alloc_id,
302305
this.machine.current_span(),
303306
diagnostics::AccessCause::Reborrow,
304307
)?;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt;
33

44
use crate::borrow_tracker::tree_borrows::diagnostics::TransitionError;
55
use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
6-
use crate::borrow_tracker::AccessKind;
6+
use crate::AccessKind;
77

88
/// The activation states of a pointer.
99
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

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

+7-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::borrow_tracker::tree_borrows::{
2424
unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap},
2525
Permission,
2626
};
27-
use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind};
27+
use crate::borrow_tracker::{GlobalState, ProtectorKind};
2828
use crate::*;
2929

3030
mod tests;
@@ -516,13 +516,15 @@ impl<'tcx> Tree {
516516
tag: BorTag,
517517
access_range: AllocRange,
518518
global: &GlobalState,
519-
span: Span, // diagnostics
519+
alloc_id: AllocId, // diagnostics
520+
span: Span, // diagnostics
520521
) -> InterpResult<'tcx> {
521522
self.perform_access(
522523
AccessKind::Write,
523524
tag,
524525
Some(access_range),
525526
global,
527+
alloc_id,
526528
span,
527529
diagnostics::AccessCause::Dealloc,
528530
)?;
@@ -545,6 +547,7 @@ impl<'tcx> Tree {
545547
TbError {
546548
conflicting_info,
547549
access_cause: diagnostics::AccessCause::Dealloc,
550+
alloc_id,
548551
error_offset: perms_range.start,
549552
error_kind,
550553
accessed_info,
@@ -576,6 +579,7 @@ impl<'tcx> Tree {
576579
tag: BorTag,
577580
access_range: Option<AllocRange>,
578581
global: &GlobalState,
582+
alloc_id: AllocId, // diagnostics
579583
span: Span, // diagnostics
580584
access_cause: diagnostics::AccessCause, // diagnostics
581585
) -> InterpResult<'tcx> {
@@ -628,6 +632,7 @@ impl<'tcx> Tree {
628632
TbError {
629633
conflicting_info,
630634
access_cause,
635+
alloc_id,
631636
error_offset: perms_range.start,
632637
error_kind,
633638
accessed_info,

src/tools/miri/src/concurrency/data_race.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ impl VClockAlloc {
812812
| MiriMemoryKind::Miri
813813
| MiriMemoryKind::C
814814
| MiriMemoryKind::WinHeap
815+
| MiriMemoryKind::WinLocal
815816
| MiriMemoryKind::Mmap,
816817
)
817818
| MemoryKind::Stack => {
@@ -820,7 +821,8 @@ impl VClockAlloc {
820821
alloc_timestamp.span = current_span;
821822
(alloc_timestamp, alloc_index)
822823
}
823-
// Other global memory should trace races but be allocated at the 0 timestamp.
824+
// Other global memory should trace races but be allocated at the 0 timestamp
825+
// (conceptually they are allocated before everything).
824826
MemoryKind::Machine(
825827
MiriMemoryKind::Global
826828
| MiriMemoryKind::Machine
@@ -1673,8 +1675,8 @@ impl GlobalState {
16731675
vector: VectorIdx,
16741676
) -> String {
16751677
let thread = self.vector_info.borrow()[vector];
1676-
let thread_name = thread_mgr.get_thread_name(thread);
1677-
format!("thread `{}`", String::from_utf8_lossy(thread_name))
1678+
let thread_name = thread_mgr.get_thread_display_name(thread);
1679+
format!("thread `{thread_name}`")
16781680
}
16791681

16801682
/// Acquire a lock, express that the previous call of

src/tools/miri/src/concurrency/thread.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,18 @@ pub type StackEmptyCallback<'mir, 'tcx> =
160160
Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>>>;
161161

162162
impl<'mir, 'tcx> Thread<'mir, 'tcx> {
163-
/// Get the name of the current thread, or `<unnamed>` if it was not set.
164-
fn thread_name(&self) -> &[u8] {
165-
if let Some(ref thread_name) = self.thread_name { thread_name } else { b"<unnamed>" }
163+
/// Get the name of the current thread if it was set.
164+
fn thread_name(&self) -> Option<&[u8]> {
165+
self.thread_name.as_deref()
166+
}
167+
168+
/// Get the name of the current thread for display purposes; will include thread ID if not set.
169+
fn thread_display_name(&self, id: ThreadId) -> String {
170+
if let Some(ref thread_name) = self.thread_name {
171+
String::from_utf8_lossy(thread_name).into_owned()
172+
} else {
173+
format!("unnamed-{}", id.index())
174+
}
166175
}
167176

168177
/// Return the top user-relevant frame, if there is one.
@@ -205,7 +214,7 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> {
205214
write!(
206215
f,
207216
"{}({:?}, {:?})",
208-
String::from_utf8_lossy(self.thread_name()),
217+
String::from_utf8_lossy(self.thread_name().unwrap_or(b"<unnamed>")),
209218
self.state,
210219
self.join_status
211220
)
@@ -572,10 +581,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
572581
}
573582

574583
/// Get the name of the given thread.
575-
pub fn get_thread_name(&self, thread: ThreadId) -> &[u8] {
584+
pub fn get_thread_name(&self, thread: ThreadId) -> Option<&[u8]> {
576585
self.threads[thread].thread_name()
577586
}
578587

588+
pub fn get_thread_display_name(&self, thread: ThreadId) -> String {
589+
self.threads[thread].thread_display_name(thread)
590+
}
591+
579592
/// Put the thread into the blocked state.
580593
fn block_thread(&mut self, thread: ThreadId) {
581594
let state = &mut self.threads[thread].state;
@@ -969,18 +982,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
969982
}
970983

971984
#[inline]
972-
fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: &[u16]) {
973-
let this = self.eval_context_mut();
974-
975-
// The Windows `GetThreadDescription` shim to get the thread name isn't implemented, so being lossy is okay.
976-
// This is only read by diagnostics, which already use `from_utf8_lossy`.
977-
this.machine
978-
.threads
979-
.set_thread_name(thread, String::from_utf16_lossy(new_thread_name).into_bytes());
980-
}
981-
982-
#[inline]
983-
fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8]
985+
fn get_thread_name<'c>(&'c self, thread: ThreadId) -> Option<&[u8]>
984986
where
985987
'mir: 'c,
986988
{

0 commit comments

Comments
 (0)