Auto merge of #122246 - RalfJung:miri, r=RalfJung

Miri subtree update

r? `@ghost`

`@WaffleLapkin` when this lands, setting `MIRI_TEMP` should not be needed any more on the dev desktops.
This commit is contained in:
bors 2024-03-10 09:40:39 +00:00
commit 3521a2f2f3
36 changed files with 239 additions and 260 deletions

View File

@ -2485,6 +2485,7 @@ dependencies = [
"regex",
"rustc_version",
"smallvec",
"tempfile",
"ui_test 0.21.2",
]

View File

@ -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

View File

@ -497,6 +497,7 @@ dependencies = [
"regex",
"rustc_version",
"smallvec",
"tempfile",
"ui_test",
]

View File

@ -45,6 +45,7 @@ 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)].
@ -52,7 +53,7 @@ lazy_static = "1.4.0"
rustc_private = true
[[test]]
name = "compiletest"
name = "ui"
harness = false
[features]

View File

@ -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

View File

@ -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

View File

@ -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} ...");
// 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());
// 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());
}
}
// 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[..])
}
}

View File

@ -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(())
}
}

View File

@ -1 +1 @@
1a1876c9790f168fb51afa335a7ba3e6fc267d75
4d4bb491b65c300835442f6cb4f34fc9a5685c26

View File

@ -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!");

View File

@ -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 },
)?;

View File

@ -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 },
)?;
}

View File

@ -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(

View File

@ -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",
];

View File

@ -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
}

View File

@ -287,13 +287,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)?) {

View File

@ -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 {

View File

@ -183,9 +183,9 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",

View File

@ -1,29 +0,0 @@
//@ignore-target-windows: No libc on Windows
//@compile-flags: -Zmiri-disable-abi-check
//! Unwinding past the top frame of a stack is Undefined Behavior.
#![feature(c_unwind)]
use std::{mem, ptr};
extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
//~^ ERROR: unwinding past the topmost frame of the stack
panic!()
}
fn main() {
unsafe {
let mut native: libc::pthread_t = mem::zeroed();
let attr: libc::pthread_attr_t = mem::zeroed();
// assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
// Cast to avoid inserting abort-on-unwind.
let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void =
thread_start;
let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void =
mem::transmute(thread_start);
assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
}
}

View File

@ -1,21 +0,0 @@
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 '<unnamed>' panicked at $DIR/unwind_top_of_stack.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: Undefined Behavior: unwinding past the topmost frame of the stack
--> $DIR/unwind_top_of_stack.rs:LL:CC
|
LL | / extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
LL | |
LL | | panic!()
LL | | }
| |_^ unwinding past the topmost frame of the stack
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC
error: aborting due to 1 previous error

View File

@ -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`.

View File

@ -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
|

View File

@ -19,7 +19,6 @@ fn main() {
after_call = {
Return()
}
}
}

View File

@ -14,7 +14,7 @@ LL | | let _unit: ();
LL | | {
LL | | let non_copy = S(42);
... |
LL | |
LL | | }
LL | | }
| |_____^
help: <TAG> is this argument

View File

@ -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

View File

@ -1,4 +1,3 @@
//@compile-flags: -Zmiri-disable-abi-check
#![feature(c_unwind)]
#[no_mangle]

View File

@ -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

View File

@ -1,12 +0,0 @@
//@compile-flags: -Zmiri-disable-abi-check
// This feature is required to trigger the error using the "C" ABI.
#![feature(c_unwind)]
extern "C" {
fn miri_start_unwind(payload: *mut u8) -> !;
}
fn main() {
unsafe { miri_start_unwind(&mut 0) }
//~^ ERROR: unwinding past a stack frame that does not allow unwinding
}

View File

@ -1,17 +0,0 @@
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.
error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
--> $DIR/bad_miri_start_unwind.rs:LL:CC
|
LL | unsafe { miri_start_unwind(&mut 0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/bad_miri_start_unwind.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@ -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!();

View File

@ -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;

View File

@ -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();
}

View File

@ -1,24 +0,0 @@
//@compile-flags: -Zmiri-disable-abi-check
#![feature(core_intrinsics)]
fn main() {
fn foo() {}
extern "C" fn try_fn(ptr: *mut u8) {
assert!(ptr.is_null());
}
extern "Rust" {
fn malloc(size: usize) -> *mut std::ffi::c_void;
}
unsafe {
let _ = malloc(0);
std::mem::transmute::<fn(), extern "C" fn()>(foo)();
std::intrinsics::catch_unwind(
std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
std::ptr::null_mut(),
|_, _| unreachable!(),
);
}
}

View File

@ -1,2 +0,0 @@
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.

View File

@ -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();
}

View File

@ -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,7 +216,13 @@ 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());
@ -219,7 +230,7 @@ fn ui(mode: Mode, path: &str, target: &str, with_dependencies: 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(),
)?;
}