Skip to content

Commit c3ec7ba

Browse files
authored
Unrolled build for #158501
Rollup merge of #158501 - RalfJung:miri, r=RalfJung miri subtree update Subtree update of `miri` to rust-lang/miri@97eec7c. Created using https://github.com/rust-lang/josh-sync. r? @ghost
2 parents 8b95a26 + 8e4a0e1 commit c3ec7ba

69 files changed

Lines changed: 1194 additions & 253 deletions

File tree

Some content is hidden

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

src/tools/miri/README.md

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,38 @@ available (which affects `cfg(target_feature)`), and it tells Miri to consider t
171171
that the interpreted program runs on as having the feature available (meaning the code is allowed to
172172
invoke the corresponding intrinsics).
173173

174+
### Nextest integration
175+
176+
Miri can be combined with [`cargo-nextest`](https://nexte.st):
177+
178+
```
179+
cargo install --locked cargo-nextest
180+
cargo miri nextest run
181+
```
182+
183+
Nextest spawns a separate instance of Miri for each test, which has several advantages:
184+
- Tests can run in parallel. Miri itself only uses a single thread per interpreter so this can
185+
give a massive speedup (but see the caveat below).
186+
- Tests do not stop when a single problem is found. Miri aborts execution when it encounters
187+
Undefined Behavior or an unsupported operation (there is often not really any way to continue),
188+
so once a single test fails, the remaining tests cannot be executed. Nextest's process-per-test
189+
model means that you end up with a full list of which tests worked in Miri and which tests had a
190+
problem.
191+
192+
However, there is also a big caveat: Miri will [re-compile the test crate every time it is
193+
invoked](https://github.com/rust-lang/miri/issues/5013), which means a crate with N tests will be
194+
compiled N+1 times. If the test crate takes a long time to build, this can outweigh the benefits of
195+
parallelization.
196+
197+
For more information about nextest, see the [`cargo-nextest` Miri
198+
documentation](https://nexte.st/book/miri.html).
199+
200+
Note: Nextest's one-test-per-process model means that `cargo miri test` is able to detect data
201+
races where two tests race on a shared resource, but `cargo miri nextest run` will not detect
202+
such races.
203+
204+
Note: `cargo-nextest` [does not support doctests](https://github.com/nextest-rs/nextest/issues/16).
205+
174206
### Testing multiple different executions
175207

176208
Certain parts of the execution are picked randomly by Miri, such as the exact base address
@@ -184,6 +216,7 @@ MIRIFLAGS="-Zmiri-many-seeds" cargo miri test # tries the seeds in 0..64
184216
MIRIFLAGS="-Zmiri-many-seeds=0..16" cargo miri test
185217
```
186218

219+
Miri will test the given range of seeds with parallel interpreter instances.
187220
The default of 64 different seeds can be quite slow, so you often want to specify a smaller range.
188221

189222
### Running Miri on CI
@@ -243,26 +276,6 @@ However, even for targets that we do support, the degree of support for accessin
243276
(such as the file system) differs between targets: generally, Linux targets have the best support,
244277
and macOS targets are usually on par. Windows is supported less well.
245278

246-
### Running tests in parallel
247-
248-
Though it implements Rust threading, Miri itself is a single-threaded interpreter
249-
(it works like a multi-threaded OS on a single-core CPU).
250-
This means that when running `cargo miri test`, you will probably see a dramatic
251-
increase in the amount of time it takes to run your whole test suite due to the
252-
inherent interpreter slowdown and a loss of parallelism.
253-
254-
You can get your test suite's parallelism back by running `cargo miri nextest run -jN`
255-
(note that you will need [`cargo-nextest`](https://nexte.st) installed).
256-
This works because `cargo-nextest` collects a list of all tests then launches a
257-
separate `cargo miri run` for each test. For more information about nextest, see the
258-
[`cargo-nextest` Miri documentation](https://nexte.st/book/miri.html).
259-
260-
Note: This one-test-per-process model means that `cargo miri test` is able to detect data
261-
races where two tests race on a shared resource, but `cargo miri nextest run` will not detect
262-
such races.
263-
264-
Note: `cargo-nextest` does not support doctests, see https://github.com/nextest-rs/nextest/issues/16
265-
266279
### Directly invoking the `miri` driver
267280

268281
The recommended way to invoke Miri is via `cargo miri`. Directly invoking the underlying `miri`

src/tools/miri/cargo-miri/src/phases.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Examples:
3636
This will print the path to the generated sysroot (and nothing else) on stdout.
3737
stderr will still contain progress information about how the build is doing.
3838
39+
For documentation on `-Zmiri-...` flags, see Miri's README.md, available at:
40+
- $(rustc --print sysroot)/share/doc/miri/README.md
41+
- https://github.com/rust-lang/miri/blob/master/README.md
3942
";
4043

4144
fn show_help() {

src/tools/miri/ci/ci.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ case $HOST_TARGET in
168168
MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests
169169
MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests
170170
MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests
171+
MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-netbsd run_tests_minimal hello
171172
;;
172173
armv7-unknown-linux-gnueabihf)
173174
# Host

src/tools/miri/priroda/src/main.rs

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extern crate rustc_data_structures;
66
extern crate rustc_driver;
77
extern crate rustc_hir;
88
extern crate rustc_hir_analysis;
9+
extern crate rustc_index;
910
extern crate rustc_interface;
1011
extern crate rustc_log;
1112
extern crate rustc_middle;
@@ -19,13 +20,15 @@ use std::path::PathBuf;
1920
use miri::*;
2021
use rustc_driver::Compilation;
2122
use rustc_hir::attrs::CrateType;
23+
use rustc_index::IndexVec;
2224
use rustc_interface::interface;
2325
use rustc_middle::mir;
26+
use rustc_middle::mir::{Local, VarDebugInfoContents};
2427
use rustc_middle::ty::TyCtxt;
2528
use rustc_session::EarlyDiagCtxt;
2629
use rustc_session::config::ErrorOutputType;
27-
use rustc_span::Span;
2830
use rustc_span::source_map::SourceMap;
31+
use rustc_span::{Span, Symbol};
2932

3033
fn find_sysroot() -> String {
3134
std::env::var("MIRI_SYSROOT")
@@ -129,6 +132,11 @@ struct PrirodaContext<'tcx> {
129132
last_location: Option<SourceLocation>,
130133
}
131134

135+
struct LocalDesc {
136+
name: Option<Symbol>,
137+
local: Local,
138+
ty: String,
139+
}
132140
/// Controls when execution returns to the frontend.
133141
enum ResumeMode {
134142
/// Stop at the next visible MIR instruction.
@@ -336,15 +344,49 @@ impl<'tcx> PrirodaContext<'tcx> {
336344
}
337345
}
338346

339-
/// Returns the names of all user-visible locals in the innermost stack frame.
347+
/// Returns structured descriptions for locals in the innermost stack frame.
340348
///
341-
/// Uses `var_debug_info` from the MIR body, which is the same source that
342-
/// DWARF debug info is built from, so the names match what the user wrote.
343-
fn list_locals(&self) -> Vec<String> {
349+
/// Starts from all MIR locals, then enriches them with source names from
350+
/// `var_debug_info` when a debug entry maps directly to a whole local.
351+
fn list_locals(&self) -> Vec<LocalDesc> {
344352
let Some(frame) = self.ecx.active_thread_stack().last() else {
345353
return Vec::new();
346354
};
347-
frame.body().var_debug_info.iter().map(|info| info.name.to_string()).collect()
355+
356+
self.local_desc_map(frame).into_iter().collect()
357+
}
358+
359+
fn local_desc_map(
360+
&self,
361+
frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>,
362+
) -> IndexVec<Local, LocalDesc> {
363+
// Initialize one description per MIR local so the table can be indexed by Local.
364+
let mut locals: IndexVec<Local, LocalDesc> = frame
365+
.body()
366+
.local_decls
367+
.iter_enumerated()
368+
.map(|(id, local_decl)| {
369+
LocalDesc { name: None, local: id, ty: local_decl.ty.to_string() }
370+
})
371+
.collect();
372+
373+
// FIXME: Some debug-info entries do not have a backing MIR local, for example
374+
// because the source variable was optimized out or is represented as a
375+
// projection. This local-indexed table cannot represent those entries yet;
376+
// the final locals list should become a `Vec<LocalDesc>` with `id : Option<Local>`, `id`
377+
// could be renamed to `local`.
378+
379+
// Attach source names from debug info when the debug entry maps directly to a whole MIR local.
380+
for var_debug_info in &frame.body().var_debug_info {
381+
if let VarDebugInfoContents::Place(place) = var_debug_info.value
382+
&& let Some(local) = place.as_local()
383+
&& locals[local].name.is_none()
384+
{
385+
locals[local].name = Some(var_debug_info.name);
386+
}
387+
}
388+
389+
locals
348390
}
349391
}
350392

@@ -366,7 +408,7 @@ enum BreakpointSetResult {
366408
enum CommandResult {
367409
ExecutionStopped(StepResult),
368410
BreakpointResult(BreakpointSetResult),
369-
Locals(Vec<String>),
411+
Locals(Vec<LocalDesc>),
370412
// FIXME: distinguish terminating the debugger session from disconnecting a
371413
// frontend and terminating the interpreted program once multiple frontends exist.
372414
TerminateSession,
@@ -403,12 +445,21 @@ impl Cli {
403445

404446
BreakpointSetResult::Duplicate => println!("Duplicate breakpoint"),
405447
},
406-
CommandResult::Locals(names) =>
407-
if names.is_empty() {
448+
CommandResult::Locals(locals_desc) =>
449+
if locals_desc.is_empty() {
408450
println!("no locals");
409451
} else {
410-
for name in &names {
411-
println!("{name}");
452+
for local_desc in &locals_desc {
453+
let mut name_str = "None".to_string();
454+
if let Some(name) = local_desc.name {
455+
name_str = name.to_string();
456+
}
457+
println!(
458+
"Name: {}, Id: _{}, Ty: {}",
459+
name_str,
460+
local_desc.local.index(),
461+
local_desc.ty,
462+
);
412463
}
413464
},
414465
CommandResult::TerminateSession => {
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_in_function.rs:5
22
(priroda) Hit breakpoint
33
{MANIFEST_DIR}/tests/ui/locals_in_function.rs:5
4-
(priroda) x
5-
y
4+
(priroda) Name: None, Id: _0, Ty: ()
5+
Name: x, Id: _1, Ty: i32
6+
Name: y, Id: _2, Ty: bool
7+
Name: None, Id: _3, Ty: (i32, bool)
8+
Name: None, Id: _4, Ty: i32
9+
Name: None, Id: _5, Ty: bool
610
(priroda) quitting

src/tools/miri/rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
01f54e80e888b66d6486a3a95d481b87353016df
1+
16761606d606b6ec4d0c88fc9251670742ad9fd2

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,9 @@ impl<'tcx> Tree {
574574
// Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
575575
// Related to https://github.com/rust-lang/rust/issues/55005.
576576
&& !perm.permission.is_cell()
577-
// Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
577+
// Only trigger UB if the accessed bit is set, i.e. if the protector
578+
// is actually protecting this offset. See #4579. Note that this
579+
// takes into account the access we just did above!
578580
&& perm.accessed
579581
{
580582
Err(TbError {

src/tools/miri/src/helpers.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,13 @@ pub fn iter_exported_symbols<'tcx>(
129129
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
130130
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
131131
};
132-
if exported {
132+
// FIXME: `#[no_mangle]` makes no sense on a generic item, but still causes it to be
133+
// considered "extern". Remove this once `no_mangle_generic_items` is a hard error.
134+
let exported_mono = exported && {
135+
let generics = tcx.generics_of(def_id);
136+
!generics.requires_monomorphization(tcx)
137+
};
138+
if exported_mono {
133139
f(LOCAL_CRATE, def_id.into())?;
134140
}
135141
}

src/tools/miri/src/shims/aarch64.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,45 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
146146
}
147147
}
148148

149+
// Signed saturating doubling multiply returning the high half.
150+
//
151+
// Used by the `vqdmulh*` functions.
152+
//
153+
// This LLVM intrinsic multiplies the values of corresponding elements of the two source
154+
// vector registers (which are signed integers), doubles the results, places the most significant half of the
155+
// final results (using a saturating cast to fit the element type) into a vector, and writes the vector to the destination register.
156+
//
157+
// https://developer.arm.com/architectures/instruction-sets/intrinsics#f:@navigationhierarchiessimdisa=[Neon]&q=vqdmulh
158+
name if name.starts_with("neon.sqdmulh.") => {
159+
let [left, right] =
160+
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
161+
162+
let (left, left_len) = this.project_to_simd(left)?;
163+
let (right, right_len) = this.project_to_simd(right)?;
164+
let (dest, dest_len) = this.project_to_simd(dest)?;
165+
assert_eq!(left_len, right_len);
166+
assert_eq!(left_len, dest_len);
167+
168+
let elem_size = dest.layout.field(this, 0).size;
169+
let bits = elem_size.bits();
170+
let min = elem_size.signed_int_min();
171+
let max = elem_size.signed_int_max();
172+
173+
for i in 0..dest_len {
174+
let a = this.read_scalar(&this.project_index(&left, i)?)?.to_int(elem_size)?;
175+
let b = this.read_scalar(&this.project_index(&right, i)?)?.to_int(elem_size)?;
176+
177+
// Uses i128 arithmetic, which cannot overflow because the intrinsic takes at most i32.
178+
let doubled = a.strict_mul(b).strict_mul(2);
179+
let res = (doubled >> bits).clamp(min, max);
180+
181+
this.write_scalar(
182+
Scalar::from_int(res, elem_size),
183+
&this.project_index(&dest, i)?,
184+
)?;
185+
}
186+
}
187+
149188
// Vector table lookup: each index selects a byte from the 16-byte table, out-of-range -> 0.
150189
// Used to implement vtbl1_u8 function.
151190
// LLVM does not have a portable shuffle that takes non-const indices

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -840,18 +840,46 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
840840
}
841841

842842
"mmap" => {
843-
let [addr, length, prot, flags, fd, offset] =
844-
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
843+
let [addr, length, prot, flags, fd, offset] = this.check_shim_sig(
844+
shim_sig!(extern "C" fn(*mut _, usize, i32, i32, i32, libc::off_t) -> *mut _),
845+
link_name,
846+
abi,
847+
args,
848+
)?;
845849
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
846850
let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
847851
this.write_scalar(ptr, dest)?;
848852
}
849853
"munmap" => {
850-
let [addr, length] =
851-
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
854+
let [addr, length] = this.check_shim_sig(
855+
shim_sig!(extern "C" fn(*mut _, usize) -> i32),
856+
link_name,
857+
abi,
858+
args,
859+
)?;
852860
let result = this.munmap(addr, length)?;
853861
this.write_scalar(result, dest)?;
854862
}
863+
"mprotect" => {
864+
let [addr, length, prot] = this.check_shim_sig(
865+
shim_sig!(extern "C" fn(*mut _, usize, i32) -> i32),
866+
link_name,
867+
abi,
868+
args,
869+
)?;
870+
let result = this.mprotect(addr, length, prot)?;
871+
this.write_scalar(result, dest)?;
872+
}
873+
"madvise" => {
874+
let [addr, length, advice] = this.check_shim_sig(
875+
shim_sig!(extern "C" fn(*mut _, usize, i32) -> i32),
876+
link_name,
877+
abi,
878+
args,
879+
)?;
880+
let result = this.madvise(addr, length, advice)?;
881+
this.write_scalar(result, dest)?;
882+
}
855883

856884
"reallocarray" => {
857885
// Currently this function does not exist on all Unixes, e.g. on macOS.
@@ -1410,7 +1438,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
14101438
let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
14111439
this.write_null(dest)?;
14121440
}
1413-
"sigaction" | "mprotect" if this.frame_in_std() => {
1441+
"sigaction" if this.frame_in_std() => {
14141442
let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
14151443
this.write_null(dest)?;
14161444
}

0 commit comments

Comments
 (0)