Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miri subtree update #122246

Merged
merged 45 commits into from
Mar 10, 2024
Merged
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
81fed2f
remove some flags that haven't had an effect in a while
RalfJung Mar 2, 2024
c1a5906
remove the ability to disable ABI checking
RalfJung Mar 2, 2024
32643dc
Fix .\miri fmt on Windows
RossSmyth Feb 26, 2024
cfc10f0
fix MIRI_LOG=info not setting the level for miri itself
RalfJung Mar 3, 2024
3041c78
log when we change the active thread
RalfJung Mar 3, 2024
983c2c5
do not rely on tracing's scope exit logging, it is wrong
RalfJung Mar 3, 2024
f51f923
Auto merge of #3348 - RalfJung:miri-thread-logging, r=RalfJung
bors Mar 3, 2024
83e2e2d
nits and typos
RalfJung Mar 3, 2024
f47732b
Auto merge of #3330 - RossSmyth:win-fmt, r=RalfJung
bors Mar 3, 2024
fbafd36
disable diagnostic deduplication
RalfJung Mar 3, 2024
d5f31bd
implement manual deduplication for isolation-error=warn-nobacktrace
RalfJung Mar 4, 2024
f70feaf
linux-futex test: add comment
RalfJung Mar 4, 2024
ede97c6
Auto merge of #3339 - RalfJung:remove-old-flags, r=saethlin
bors Mar 4, 2024
e87f825
Auto merge of #3351 - RalfJung:diagnostic-dedup-considered-harmful, r…
bors Mar 4, 2024
974446e
we properly rebuild the cache now when MIRI_LIB_SRC contents change
RalfJung Mar 4, 2024
8851f3c
Auto merge of #3354 - RalfJung:MIRI_LIB_SRC-change, r=RalfJung
bors Mar 4, 2024
75f6694
Use cargo miri clean in build-all-targets.sh
saethlin Mar 4, 2024
5b05be1
Auto merge of #3355 - saethlin:cargo-miri-clean, r=RalfJung
bors Mar 4, 2024
a477cf4
Conjob → Cronjob
RalfJung Mar 4, 2024
45d955e
reorder rustc crate imports a bit
RalfJung Mar 2, 2024
4fdb215
Auto merge of #3356 - RalfJung:typo, r=RalfJung
bors Mar 4, 2024
790287a
Auto merge of #3357 - RalfJung:imports, r=RalfJung
bors Mar 4, 2024
2b40181
give macOS even more time to sleep
RalfJung Mar 4, 2024
65ec028
Auto merge of #3358 - RalfJung:zzz, r=RalfJung
bors Mar 4, 2024
5294dd8
Bump mio from 0.8.10 to 0.8.11 in /test_dependencies
dependabot[bot] Mar 4, 2024
e88704e
Auto merge of #3359 - rust-lang:dependabot/cargo/test_dependencies/mi…
bors Mar 4, 2024
033c1e0
Auto merge of #3340 - RalfJung:no-disable-abi-check, r=oli-obk
bors Mar 6, 2024
4b955f1
Preparing for merge from rustc
RalfJung Mar 6, 2024
a5a8437
Merge from rustc
RalfJung Mar 6, 2024
3c2318c
make remaining FloatTy matches exhaustive
RalfJung Mar 6, 2024
305d2b0
Auto merge of #3363 - RalfJung:rustup, r=RalfJung
bors Mar 6, 2024
c301bf9
Preparing for merge from rustc
Mar 8, 2024
2ebf9ec
Merge from rustc
Mar 8, 2024
fcd2efe
fix clippy lints
RalfJung Mar 8, 2024
4db028f
Auto merge of #3365 - rust-lang:rustup-2024-03-08, r=RalfJung
bors Mar 8, 2024
4235ec5
compiletest: create fresh tempdir for tests to use
RalfJung Mar 8, 2024
52db5f6
Preparing for merge from rustc
Mar 9, 2024
e720147
Merge from rustc
Mar 9, 2024
91644dd
fmt
Mar 9, 2024
cabac98
Auto merge of #3366 - RalfJung:tempdir, r=oli-obk
bors Mar 9, 2024
00be352
rename tests/compiletest → tests/ui
RalfJung Mar 9, 2024
b0fad9a
Auto merge of #3368 - RalfJung:ui, r=RalfJung
bors Mar 9, 2024
862f918
fix clippy lints
RalfJung Mar 9, 2024
0ebb78f
Auto merge of #3367 - rust-lang:rustup-2024-03-09, r=RalfJung
bors Mar 9, 2024
9a308d4
update lockfile
RalfJung Mar 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -2493,6 +2493,7 @@ dependencies = [
"regex",
"rustc_version",
"smallvec",
"tempfile",
"ui_test 0.21.2",
]

2 changes: 1 addition & 1 deletion src/tools/miri/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -187,7 +187,7 @@ jobs:
run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
- name: setup bot git name and email
run: |
git config --global user.name 'The Miri Conjob Bot'
git config --global user.name 'The Miri Cronjob Bot'
git config --global user.email 'miri@cron.bot'
- name: get changes from rustc
run: ./miri rustc-pull
1 change: 1 addition & 0 deletions src/tools/miri/Cargo.lock
Original file line number Diff line number Diff line change
@@ -497,6 +497,7 @@ dependencies = [
"regex",
"rustc_version",
"smallvec",
"tempfile",
"ui_test",
]

3 changes: 2 additions & 1 deletion src/tools/miri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -45,14 +45,15 @@ ui_test = "0.21.1"
rustc_version = "0.4"
regex = "1.5.5"
lazy_static = "1.4.0"
tempfile = "3"

[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)].
# See https://github.com/rust-analyzer/rust-analyzer/pull/7891
rustc_private = true

[[test]]
name = "compiletest"
name = "ui"
harness = false

[features]
12 changes: 3 additions & 9 deletions src/tools/miri/README.md
Original file line number Diff line number Diff line change
@@ -318,8 +318,8 @@ environment variable. We first document the most relevant and most commonly used
and `warn-nobacktrace` are the supported actions. The default is to `abort`,
which halts the machine. Some (but not all) operations also support continuing
execution with a "permission denied" error being returned to the program.
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
verbose. `hide` hides the warning entirely.
`warn` prints a full backtrace each time that happens; `warn-nobacktrace` is less
verbose and shown at most once per operation. `hide` hides the warning entirely.
* `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
any way.
@@ -359,8 +359,6 @@ The remaining flags are for advanced use only, and more likely to change or be r
Some of these are **unsound**, which means they can lead
to Miri failing to detect cases of undefined behavior in a program.

* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag
is **unsound**. This flag is **deprecated**.
* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you
can focus on other failures, but it means Miri can miss bugs in your program.
Using this flag is **unsound**.
@@ -465,11 +463,7 @@ Moreover, Miri recognizes some environment variables:
* `MIRI_LIB_SRC` defines the directory where Miri expects the sources of the
standard library that it will build and use for interpretation. This directory
must point to the `library` subdirectory of a `rust-lang/rust` repository
checkout. Note that changing files in that directory does not automatically
trigger a re-build of the standard library; you have to clear the Miri build
cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`;
on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`;
and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`).
checkout.
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the
automatically created sysroot. For directly invoking the Miri driver, this variable (or a
2 changes: 1 addition & 1 deletion src/tools/miri/ci/build-all-targets.sh
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ PLATFORM_SUPPORT_FILE=$(rustc +miri --print sysroot)/share/doc/rust/html/rustc/p

for target in $(python3 ci/scrape-targets.py $PLATFORM_SUPPORT_FILE); do
# Wipe the cache before every build to minimize disk usage
rm -rf ~/.cache/miri
cargo +miri miri clean
if cargo +miri miri setup --target $target 2>&1 | tee failures/$target; then
# If the build succeeds, delete its output. If we have output, a build failed.
rm $FAILS_DIR/$target
50 changes: 20 additions & 30 deletions src/tools/miri/miri-script/src/commands.rs
Original file line number Diff line number Diff line change
@@ -510,11 +510,11 @@ impl Command {
let miri_flags = flagsplit(&miri_flags);
let toolchain = &e.toolchain;
let extra_flags = &e.cargo_extra_flags;
let edition_flags = (!have_edition).then_some("--edition=2021"); // keep in sync with `compiletest.rs`.`
let edition_flags = (!have_edition).then_some("--edition=2021"); // keep in sync with `tests/ui.rs`.`
if dep {
cmd!(
e.sh,
"cargo +{toolchain} --quiet test --test compiletest {extra_flags...} --manifest-path {miri_manifest} -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
"cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
).quiet().run()?;
} else {
cmd!(
@@ -526,37 +526,27 @@ impl Command {
}

fn fmt(flags: Vec<OsString>) -> Result<()> {
use itertools::Itertools;

let e = MiriEnv::new()?;
let toolchain = &e.toolchain;
let config_path = path!(e.miri_dir / "rustfmt.toml");

let mut cmd = cmd!(
e.sh,
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
);
eprintln!("$ {cmd} ...");

// Add all the filenames to the command.
// FIXME: `rustfmt` will follow the `mod` statements in these files, so we get a bunch of
// duplicate diffs.
for item in WalkDir::new(&e.miri_dir).into_iter().filter_entry(|entry| {
let name = entry.file_name().to_string_lossy();
let ty = entry.file_type();
if ty.is_file() {
name.ends_with(".rs")
} else {
// dir or symlink. skip `target` and `.git`.
&name != "target" && &name != ".git"
}
}) {
let item = item?;
if item.file_type().is_file() {
cmd = cmd.arg(item.into_path());
}
}
// Collect each rust file in the miri repo.
let files = WalkDir::new(&e.miri_dir)
.into_iter()
.filter_entry(|entry| {
let name = entry.file_name().to_string_lossy();
let ty = entry.file_type();
if ty.is_file() {
name.ends_with(".rs")
} else {
// dir or symlink. skip `target` and `.git`.
&name != "target" && &name != ".git"
}
})
.filter_ok(|item| item.file_type().is_file())
.map_ok(|item| item.into_path());

// We want our own error message, repeating the command is too much.
cmd.quiet().run().map_err(|_| anyhow!("`rustfmt` failed"))?;
Ok(())
e.format_files(files, &e.toolchain[..], &config_path, &flags[..])
}
}
48 changes: 46 additions & 2 deletions src/tools/miri/miri-script/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use dunce::canonicalize;
use path_macro::path;
use xshell::{cmd, Shell};
@@ -145,4 +145,48 @@ impl MiriEnv {
.run()?;
Ok(())
}

/// Receives an iterator of files.
/// Will format each file with the miri rustfmt config.
/// Does not recursively format modules.
pub fn format_files(
&self,
files: impl Iterator<Item = Result<PathBuf, walkdir::Error>>,
toolchain: &str,
config_path: &Path,
flags: &[OsString],
) -> anyhow::Result<()> {
use itertools::Itertools;

let mut first = true;

// Format in batches as not all our files fit into Windows' command argument limit.
for batch in &files.chunks(256) {
// Build base command.
let mut cmd = cmd!(
self.sh,
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
);
if first {
// Log an abbreviating command, and only once.
eprintln!("$ {cmd} ...");
first = false;
}
// Add files.
for file in batch {
// Make it a relative path so that on platforms with extremely tight argument
// limits (like Windows), we become immune to someone cloning the repo
// 50 directories deep.
let file = file?;
let file = file.strip_prefix(&self.miri_dir)?;
cmd = cmd.arg(file);
}

// Run rustfmt.
// We want our own error message, repeating the command is too much.
cmd.quiet().run().map_err(|_| anyhow!("`rustfmt` failed"))?;
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/tools/miri/rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1a1876c9790f168fb51afa335a7ba3e6fc267d75
4d4bb491b65c300835442f6cb4f34fc9a5685c26
32 changes: 10 additions & 22 deletions src/tools/miri/src/bin/miri.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,11 @@
rustc::untranslatable_diagnostic
)]

// Some "regular" crates we want to share with rustc
#[macro_use]
extern crate tracing;

// The rustc crates we need
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
@@ -16,8 +21,6 @@ extern crate rustc_log;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_session;
#[macro_use]
extern crate tracing;

use std::env::{self, VarError};
use std::num::NonZero;
@@ -202,16 +205,12 @@ fn rustc_logger_config() -> rustc_log::LoggerConfig {
// rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`.
if tracing::Level::from_str(&var).is_ok() {
cfg.filter = Ok(format!(
"rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var}"
"rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var},miri={var}"
));
} else {
cfg.filter = Ok(var);
}
}
// Enable verbose entry/exit logging by default if MIRI_LOG is set.
if matches!(cfg.verbose_entry_exit, Err(VarError::NotPresent)) {
cfg.verbose_entry_exit = Ok(format!("1"));
}
}

cfg
@@ -342,7 +341,8 @@ fn main() {
// (`install_ice_hook` might change `RUST_BACKTRACE`.)
let env_snapshot = env::vars_os().collect::<Vec<_>>();

let args = rustc_driver::args::raw_args(&early_dcx).unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));
let args = rustc_driver::args::raw_args(&early_dcx)
.unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));

// If the environment asks us to actually be rustc, then do that.
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
@@ -408,17 +408,11 @@ fn main() {
miri_config.check_alignment = miri::AlignmentCheck::None;
} else if arg == "-Zmiri-symbolic-alignment-check" {
miri_config.check_alignment = miri::AlignmentCheck::Symbolic;
} else if arg == "-Zmiri-check-number-validity" {
eprintln!(
"WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \
since it is now enabled by default"
);
} else if arg == "-Zmiri-disable-abi-check" {
eprintln!(
"WARNING: the flag `-Zmiri-disable-abi-check` is deprecated and planned to be removed.\n\
If you have a use-case for it, please file an issue."
"WARNING: the flag `-Zmiri-disable-abi-check` no longer has any effect; \
ABI checks cannot be disabled any more"
);
miri_config.check_abi = false;
} else if arg == "-Zmiri-disable-isolation" {
if matches!(isolation_enabled, Some(true)) {
show_error!(
@@ -459,8 +453,6 @@ fn main() {
miri_config.collect_leak_backtraces = false;
} else if arg == "-Zmiri-panic-on-unsupported" {
miri_config.panic_on_unsupported = true;
} else if arg == "-Zmiri-tag-raw-pointers" {
eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default");
} else if arg == "-Zmiri-strict-provenance" {
miri_config.provenance_mode = ProvenanceMode::Strict;
} else if arg == "-Zmiri-permissive-provenance" {
@@ -476,10 +468,6 @@ fn main() {
"scalar" => RetagFields::OnlyScalar,
_ => show_error!("`-Zmiri-retag-fields` can only be `all`, `none`, or `scalar`"),
};
} else if arg == "-Zmiri-track-raw-pointers" {
eprintln!(
"WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default"
);
} else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") {
if miri_config.seed.is_some() {
show_error!("Cannot specify -Zmiri-seed multiple times!");
18 changes: 13 additions & 5 deletions src/tools/miri/src/concurrency/thread.rs
Original file line number Diff line number Diff line change
@@ -445,10 +445,13 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {

/// Set an active thread and return the id of the thread that was active before.
fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId {
let active_thread_id = self.active_thread;
self.active_thread = id;
assert!(self.active_thread.index() < self.threads.len());
active_thread_id
assert!(id.index() < self.threads.len());
info!(
"---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------",
self.get_thread_display_name(id),
self.get_thread_display_name(self.active_thread)
);
std::mem::replace(&mut self.active_thread, id)
}

/// Get the id of the currently active thread.
@@ -735,6 +738,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
for (id, thread) in threads {
debug_assert_ne!(self.active_thread, id);
if thread.state == ThreadState::Enabled {
info!(
"---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------",
self.get_thread_display_name(id),
self.get_thread_display_name(self.active_thread)
);
self.active_thread = id;
break;
}
@@ -882,7 +890,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
instance,
start_abi,
&[*func_arg],
Some(&ret_place.into()),
Some(&ret_place),
StackPopCleanup::Root { cleanup: true },
)?;

7 changes: 2 additions & 5 deletions src/tools/miri/src/eval.rs
Original file line number Diff line number Diff line change
@@ -94,8 +94,6 @@ pub struct MiriConfig {
pub unique_is_unique: bool,
/// Controls alignment checking.
pub check_alignment: AlignmentCheck,
/// Controls function [ABI](Abi) checking.
pub check_abi: bool,
/// Action for an op requiring communication with the host.
pub isolated_op: IsolatedOp,
/// Determines if memory leaks should be ignored.
@@ -162,7 +160,6 @@ impl Default for MiriConfig {
borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
unique_is_unique: false,
check_alignment: AlignmentCheck::Int,
check_abi: true,
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
ignore_leaks: false,
forwarded_env_vars: vec![],
@@ -394,7 +391,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
argv,
Scalar::from_u8(sigpipe).into(),
],
Some(&ret_place.into()),
Some(&ret_place),
StackPopCleanup::Root { cleanup: true },
)?;
}
@@ -403,7 +400,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
entry_instance,
Abi::Rust,
&[argc.into(), argv],
Some(&ret_place.into()),
Some(&ret_place),
StackPopCleanup::Root { cleanup: true },
)?;
}
44 changes: 26 additions & 18 deletions src/tools/miri/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cmp;
use std::collections::BTreeSet;
use std::iter;
use std::num::NonZero;
use std::sync::Mutex;
use std::time::Duration;

use rustc_apfloat::ieee::{Double, Single};
@@ -387,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
if this.machine.enforce_abi && callee_abi != caller_abi {
if callee_abi != caller_abi {
throw_ub_format!(
"calling a function with ABI {} using caller ABI {}",
callee_abi.name(),
@@ -399,7 +401,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mir = this.load_mir(f.def, None)?;
let dest = match dest {
Some(dest) => dest.clone(),
None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?).into(),
None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?),
};
this.push_stack_frame(f, mir, &dest, stack_pop)?;

@@ -603,9 +605,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match reject_with {
RejectOpWith::Abort => isolation_abort_error(op_name),
RejectOpWith::WarningWithoutBacktrace => {
this.tcx
.dcx()
.warn(format!("{op_name} was made to return an error due to isolation"));
// This exists to reduce verbosity; make sure we emit the warning at most once per
// operation.
static EMITTED_WARNINGS: Mutex<BTreeSet<String>> = Mutex::new(BTreeSet::new());

let mut emitted_warnings = EMITTED_WARNINGS.lock().unwrap();
if !emitted_warnings.contains(op_name) {
// First time we are seeing this.
emitted_warnings.insert(op_name.to_owned());
this.tcx
.dcx()
.warn(format!("{op_name} was made to return an error due to isolation"));
}
Ok(())
}
RejectOpWith::Warning => {
@@ -945,7 +956,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

/// Check that the ABI is what we expect.
fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
if self.eval_context_ref().machine.enforce_abi && abi != exp_abi {
if abi != exp_abi {
throw_ub_format!(
"calling a function with ABI {} using caller ABI {}",
exp_abi.name(),
@@ -1091,20 +1102,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}

let (val, status) = match src.layout.ty.kind() {
// f32
ty::Float(FloatTy::F32) =>
let ty::Float(fty) = src.layout.ty.kind() else {
bug!("float_to_int_checked: non-float input type {}", src.layout.ty)
};

let (val, status) = match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F32 =>
float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
// f64
ty::Float(FloatTy::F64) =>
FloatTy::F64 =>
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
// Nothing else
_ =>
span_bug!(
this.cur_span(),
"attempted float-to-int conversion with non-float input type {}",
src.layout.ty,
),
FloatTy::F128 => unimplemented!("f16_f128"),
};

if status.intersects(
16 changes: 10 additions & 6 deletions src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
@@ -49,8 +49,12 @@
// Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
#![recursion_limit = "256"]

extern crate either; // the one from rustc
// Some "regular" crates we want to share with rustc
extern crate either;
#[macro_use]
extern crate tracing;

// The rustc crates we need
extern crate rustc_apfloat;
extern crate rustc_ast;
extern crate rustc_const_eval;
@@ -63,11 +67,8 @@ extern crate rustc_middle;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
#[macro_use]
extern crate tracing;

// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
// Linking `rustc_driver` pulls in the required object code as the rest of the rustc crates are
// shipped only as rmeta files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

@@ -143,4 +144,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
"-Zmir-keep-place-mention",
"-Zmir-opt-level=0",
"-Zmir-enable-passes=-CheckAlignment",
// Deduplicating diagnostics means we miss events when tracking what happens during an
// execution. Let's not do that.
"-Zdeduplicate-diagnostics=no",
];
35 changes: 22 additions & 13 deletions src/tools/miri/src/machine.rs
Original file line number Diff line number Diff line change
@@ -462,9 +462,6 @@ pub struct MiriMachine<'mir, 'tcx> {
/// Whether to enforce the validity invariant.
pub(crate) validate: bool,

/// Whether to enforce [ABI](Abi) of function calls.
pub(crate) enforce_abi: bool,

/// The table of file descriptors.
pub(crate) file_handler: shims::unix::FileHandler,
/// The table of directory descriptors.
@@ -643,7 +640,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
tls: TlsData::default(),
isolated_op: config.isolated_op,
validate: config.validate,
enforce_abi: config.check_abi,
file_handler: FileHandler::new(config.mute_stdout_stderr),
dir_handler: Default::default(),
layouts,
@@ -786,7 +782,6 @@ impl VisitProvenance for MiriMachine<'_, '_> {
tcx: _,
isolated_op: _,
validate: _,
enforce_abi: _,
clock: _,
layouts: _,
static_roots: _,
@@ -934,8 +929,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
}

#[inline(always)]
fn enforce_abi(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.enforce_abi
fn enforce_abi(_ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
true
}

#[inline(always)]
@@ -1338,7 +1333,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
// If we have a borrow tracker, we also have it set up protection so that all reads *and
// writes* during this call are insta-UB.
let protected_place = if ecx.machine.borrow_tracker.is_some() {
ecx.protect_place(&place)?.into()
ecx.protect_place(place)?
} else {
// No borrow tracker.
place.clone()
@@ -1447,13 +1442,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
if ecx.machine.borrow_tracker.is_some() {
ecx.on_stack_pop(frame)?;
}
// tracing-tree can autoamtically annotate scope changes, but it gets very confused by our
// concurrency and what it prints is just plain wrong. So we print our own information
// instead. (Cc https://github.com/rust-lang/miri/issues/2266)
info!("Leaving {}", ecx.frame().instance);
Ok(())
}

#[inline(always)]
fn after_stack_pop(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
mut frame: Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
frame: Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
unwinding: bool,
) -> InterpResult<'tcx, StackPopJump> {
if frame.extra.is_user_relevant {
@@ -1463,10 +1462,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
// user-relevant frame and restore that here.)
ecx.active_thread_mut().recompute_top_user_relevant_frame();
}
let timing = frame.extra.timing.take();
let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
if let Some(profiler) = ecx.machine.profiler.as_ref() {
profiler.finish_recording_interval_event(timing.unwrap());
let res = {
// Move `frame`` into a sub-scope so we control when it will be dropped.
let mut frame = frame;
let timing = frame.extra.timing.take();
let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
if let Some(profiler) = ecx.machine.profiler.as_ref() {
profiler.finish_recording_interval_event(timing.unwrap());
}
res
};
// Needs to be done after dropping frame to show up on the right nesting level.
// (Cc https://github.com/rust-lang/miri/issues/2266)
if !ecx.active_thread_stack().is_empty() {
info!("Continuing in {}", ecx.frame().instance);
}
res
}
15 changes: 8 additions & 7 deletions src/tools/miri/src/shims/intrinsics/mod.rs
Original file line number Diff line number Diff line change
@@ -274,13 +274,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => bug!(),
};
let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> {
Ok(match x.layout.ty.kind() {
ty::Float(FloatTy::F32) => x.to_scalar().to_f32()?.is_finite(),
ty::Float(FloatTy::F64) => x.to_scalar().to_f64()?.is_finite(),
_ => bug!(
"`{intrinsic_name}` called with non-float input type {ty:?}",
ty = x.layout.ty,
),
let ty::Float(fty) = x.layout.ty.kind() else {
bug!("float_finite: non-float input type {}", x.layout.ty)
};
Ok(match fty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(),
FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(),
FloatTy::F128 => unimplemented!("f16_f128"),
})
};
match (float_finite(&a)?, float_finite(&b)?) {
2 changes: 1 addition & 1 deletion src/tools/miri/src/shims/windows/sync.rs
Original file line number Diff line number Diff line change
@@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

let id = this.init_once_get_id(init_once_op)?;
let flags = this.read_scalar(flags_op)?.to_u32()?;
let pending_place = this.deref_pointer(pending_op)?.into();
let pending_place = this.deref_pointer(pending_op)?;
let context = this.read_pointer(context_op)?;

if flags != 0 {
4 changes: 2 additions & 2 deletions src/tools/miri/test_dependencies/Cargo.lock
29 changes: 0 additions & 29 deletions src/tools/miri/tests/fail-dep/concurrency/unwind_top_of_stack.rs

This file was deleted.

This file was deleted.

8 changes: 8 additions & 0 deletions src/tools/miri/tests/fail/const-ub-checks.stderr
Original file line number Diff line number Diff line change
@@ -10,6 +10,14 @@ note: erroneous constant encountered
LL | let _x = UNALIGNED_READ;
| ^^^^^^^^^^^^^^

note: erroneous constant encountered
--> $DIR/const-ub-checks.rs:LL:CC
|
LL | let _x = UNALIGNED_READ;
| ^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0080`.
8 changes: 8 additions & 0 deletions src/tools/miri/tests/fail/erroneous_const2.stderr
Original file line number Diff line number Diff line change
@@ -10,6 +10,14 @@ note: erroneous constant encountered
LL | println!("{}", FOO);
| ^^^

note: erroneous constant encountered
--> $DIR/erroneous_const2.rs:LL:CC
|
LL | println!("{}", FOO);
| ^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

note: erroneous constant encountered
--> $DIR/erroneous_const2.rs:LL:CC
|
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ fn main() {
after_call = {
Return()
}

}
}

Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ LL | | let _unit: ();
LL | | {
LL | | let non_copy = S(42);
... |
LL | |
LL | | }
LL | | }
| |_____^
help: <TAG> is this argument
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ LL | | let _unit: ();
LL | | {
LL | | let non_copy = S(42);
... |
LL | |
LL | | }
LL | | }
| |_____^
help: the protected tag <TAG> was created here, in the initial state Reserved
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//@compile-flags: -Zmiri-disable-abi-check
#![feature(c_unwind)]

#[no_mangle]
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
WARNING: the flag `-Zmiri-disable-abi-check` is deprecated and planned to be removed.
If you have a use-case for it, please file an issue.
thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
12 changes: 0 additions & 12 deletions src/tools/miri/tests/fail/panic/bad_miri_start_unwind.rs

This file was deleted.

17 changes: 0 additions & 17 deletions src/tools/miri/tests/fail/panic/bad_miri_start_unwind.stderr

This file was deleted.

3 changes: 3 additions & 0 deletions src/tools/miri/tests/fail/panic/bad_unwind.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![feature(c_unwind)]

//! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
// The opposite version (callee does not allow unwinding) is impossible to
// even write: MIR validation catches functions that have `UnwindContinue` but
// are not allowed to unwind.

extern "C-unwind" fn unwind() {
panic!();
1 change: 1 addition & 0 deletions src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
Original file line number Diff line number Diff line change
@@ -219,6 +219,7 @@ fn wait_wake_bitset() {
t.join().unwrap();
}

// Crucial test which relies on the SeqCst fences in futex wait/wake.
fn concurrent_wait_wake() {
const FREE: i32 = 0;
const HELD: i32 = 1;
27 changes: 17 additions & 10 deletions src/tools/miri/tests/pass/concurrency/sync.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,10 @@ use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// We are expecting to sleep for 10ms. How long of a sleep we are accepting?
// Even with 1000ms we still see this test fail on macOS runners.
const MAX_SLEEP_TIME_MS: u64 = 2000;

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
@@ -66,7 +70,7 @@ fn check_conditional_variables_timed_wait_timeout() {
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(10)).unwrap();
assert!(timeout.timed_out());
let elapsed_time = now.elapsed().as_millis();
assert!(10 <= elapsed_time && elapsed_time <= 1000);
assert!(10 <= elapsed_time && elapsed_time <= MAX_SLEEP_TIME_MS.into());
}

/// Test that signaling a conditional variable when waiting with a timeout works
@@ -84,7 +88,8 @@ fn check_conditional_variables_timed_wait_notimeout() {
cvar.notify_one();
});

let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(1000)).unwrap();
let (_guard, timeout) =
cvar.wait_timeout(guard, Duration::from_millis(MAX_SLEEP_TIME_MS)).unwrap();
assert!(!timeout.timed_out());
handle.join().unwrap();
}
@@ -213,20 +218,21 @@ fn check_once() {
fn park_timeout() {
let start = Instant::now();

thread::park_timeout(Duration::from_millis(200));
thread::park_timeout(Duration::from_millis(10));
// Normally, waiting in park/park_timeout may spuriously wake up early, but we
// know Miri's timed synchronization primitives do not do that.
// We allow much longer sleeps as well since the macOS GHA runners seem very oversubscribed
// and sometimes just pause for 1 second or more.
let elapsed = start.elapsed();
assert!((200..2000).contains(&elapsed.as_millis()), "bad sleep time: {elapsed:?}");
assert!(
(10..MAX_SLEEP_TIME_MS.into()).contains(&elapsed.as_millis()),
"bad sleep time: {elapsed:?}"
);
}

fn park_unpark() {
let t1 = thread::current();
let t2 = thread::spawn(move || {
thread::park();
thread::sleep(Duration::from_millis(200));
thread::sleep(Duration::from_millis(10));
t1.unpark();
});

@@ -236,10 +242,11 @@ fn park_unpark() {
thread::park();
// Normally, waiting in park/park_timeout may spuriously wake up early, but we
// know Miri's timed synchronization primitives do not do that.
// We allow much longer sleeps as well since the macOS GHA runners seem very oversubscribed
// and sometimes just pause for 1 second or more.
let elapsed = start.elapsed();
assert!((200..2000).contains(&elapsed.as_millis()), "bad sleep time: {elapsed:?}");
assert!(
(10..MAX_SLEEP_TIME_MS.into()).contains(&elapsed.as_millis()),
"bad sleep time: {elapsed:?}"
);

t2.join().unwrap();
}
24 changes: 0 additions & 24 deletions src/tools/miri/tests/pass/function_calls/disable_abi_check.rs

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion src/tools/miri/tests/pass/shims/fs.rs
Original file line number Diff line number Diff line change
@@ -295,7 +295,7 @@ fn test_canonicalize() {
drop(File::create(&path).unwrap());

let p = canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).unwrap();
assert_eq!(p.to_string_lossy().find('.'), None);
assert_eq!(p.to_string_lossy().find("/./"), None);

remove_dir_all(&dir_path).unwrap();
}
43 changes: 29 additions & 14 deletions src/tools/miri/tests/compiletest.rs → src/tools/miri/tests/ui.rs
Original file line number Diff line number Diff line change
@@ -79,13 +79,6 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
program.args.push(flag);
}

// Add a test env var to do environment communication tests.
program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));

// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
let miri_temp = env::var_os("MIRI_TEMP").unwrap_or_else(|| env::temp_dir().into());
program.envs.push(("MIRI_TEMP".into(), Some(miri_temp)));

let mut config = Config {
target: Some(target.to_owned()),
stderr_filters: STDERR.clone(),
@@ -116,9 +109,21 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
config
}

fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> Result<()> {
fn run_tests(
mode: Mode,
path: &str,
target: &str,
with_dependencies: bool,
tmpdir: &Path,
) -> Result<()> {
let mut config = test_config(target, path, mode, with_dependencies);

// Add a test env var to do environment communication tests.
config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));

// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));

// Handle command-line arguments.
let args = ui_test::Args::test()?;
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
@@ -211,15 +216,21 @@ enum Dependencies {

use Dependencies::*;

fn ui(mode: Mode, path: &str, target: &str, with_dependencies: Dependencies) -> Result<()> {
fn ui(
mode: Mode,
path: &str,
target: &str,
with_dependencies: Dependencies,
tmpdir: &Path,
) -> Result<()> {
let msg = format!("## Running ui tests in {path} against miri for {target}");
eprintln!("{}", msg.green().bold());

let with_dependencies = match with_dependencies {
WithDependencies => true,
WithoutDependencies => false,
};
run_tests(mode, path, target, with_dependencies)
run_tests(mode, path, target, with_dependencies, tmpdir)
}

fn get_target() -> String {
@@ -230,6 +241,7 @@ fn main() -> Result<()> {
ui_test::color_eyre::install()?;

let target = get_target();
let tmpdir = tempfile::Builder::new().prefix("miri-uitest-").tempdir()?;

let mut args = std::env::args_os();

@@ -240,28 +252,31 @@ fn main() -> Result<()> {
}
}

ui(Mode::Pass, "tests/pass", &target, WithoutDependencies)?;
ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies)?;
ui(Mode::Panic, "tests/panic", &target, WithDependencies)?;
ui(Mode::Pass, "tests/pass", &target, WithoutDependencies, tmpdir.path())?;
ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies, tmpdir.path())?;
ui(Mode::Panic, "tests/panic", &target, WithDependencies, tmpdir.path())?;
ui(
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
"tests/fail",
&target,
WithoutDependencies,
tmpdir.path(),
)?;
ui(
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
"tests/fail-dep",
&target,
WithDependencies,
tmpdir.path(),
)?;
if cfg!(target_os = "linux") {
ui(Mode::Pass, "tests/extern-so/pass", &target, WithoutDependencies)?;
ui(Mode::Pass, "tests/extern-so/pass", &target, WithoutDependencies, tmpdir.path())?;
ui(
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
"tests/extern-so/fail",
&target,
WithoutDependencies,
tmpdir.path(),
)?;
}