mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
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:
commit
3521a2f2f3
@ -2485,6 +2485,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"tempfile",
|
||||||
"ui_test 0.21.2",
|
"ui_test 0.21.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
2
src/tools/miri/.github/workflows/ci.yml
vendored
2
src/tools/miri/.github/workflows/ci.yml
vendored
@ -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
|
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
|
- name: setup bot git name and email
|
||||||
run: |
|
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'
|
git config --global user.email 'miri@cron.bot'
|
||||||
- name: get changes from rustc
|
- name: get changes from rustc
|
||||||
run: ./miri rustc-pull
|
run: ./miri rustc-pull
|
||||||
|
@ -497,6 +497,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"tempfile",
|
||||||
"ui_test",
|
"ui_test",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ ui_test = "0.21.1"
|
|||||||
rustc_version = "0.4"
|
rustc_version = "0.4"
|
||||||
regex = "1.5.5"
|
regex = "1.5.5"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
tempfile = "3"
|
||||||
|
|
||||||
[package.metadata.rust-analyzer]
|
[package.metadata.rust-analyzer]
|
||||||
# This crate uses #[feature(rustc_private)].
|
# This crate uses #[feature(rustc_private)].
|
||||||
@ -52,7 +53,7 @@ lazy_static = "1.4.0"
|
|||||||
rustc_private = true
|
rustc_private = true
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "compiletest"
|
name = "ui"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -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`,
|
and `warn-nobacktrace` are the supported actions. The default is to `abort`,
|
||||||
which halts the machine. Some (but not all) operations also support continuing
|
which halts the machine. Some (but not all) operations also support continuing
|
||||||
execution with a "permission denied" error being returned to the program.
|
execution with a "permission denied" error being returned to the program.
|
||||||
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
|
`warn` prints a full backtrace each time that happens; `warn-nobacktrace` is less
|
||||||
verbose. `hide` hides the warning entirely.
|
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
|
* `-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
|
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
|
||||||
any way.
|
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
|
Some of these are **unsound**, which means they can lead
|
||||||
to Miri failing to detect cases of undefined behavior in a program.
|
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
|
* `-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.
|
can focus on other failures, but it means Miri can miss bugs in your program.
|
||||||
Using this flag is **unsound**.
|
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
|
* `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
|
standard library that it will build and use for interpretation. This directory
|
||||||
must point to the `library` subdirectory of a `rust-lang/rust` repository
|
must point to the `library` subdirectory of a `rust-lang/rust` repository
|
||||||
checkout. Note that changing files in that directory does not automatically
|
checkout.
|
||||||
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`).
|
|
||||||
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
|
* `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
|
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
|
automatically created sysroot. For directly invoking the Miri driver, this variable (or a
|
||||||
|
@ -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
|
for target in $(python3 ci/scrape-targets.py $PLATFORM_SUPPORT_FILE); do
|
||||||
# Wipe the cache before every build to minimize disk usage
|
# 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 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.
|
# If the build succeeds, delete its output. If we have output, a build failed.
|
||||||
rm $FAILS_DIR/$target
|
rm $FAILS_DIR/$target
|
||||||
|
@ -510,11 +510,11 @@ impl Command {
|
|||||||
let miri_flags = flagsplit(&miri_flags);
|
let miri_flags = flagsplit(&miri_flags);
|
||||||
let toolchain = &e.toolchain;
|
let toolchain = &e.toolchain;
|
||||||
let extra_flags = &e.cargo_extra_flags;
|
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 {
|
if dep {
|
||||||
cmd!(
|
cmd!(
|
||||||
e.sh,
|
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()?;
|
).quiet().run()?;
|
||||||
} else {
|
} else {
|
||||||
cmd!(
|
cmd!(
|
||||||
@ -526,37 +526,27 @@ impl Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fmt(flags: Vec<OsString>) -> Result<()> {
|
fn fmt(flags: Vec<OsString>) -> Result<()> {
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
let e = MiriEnv::new()?;
|
let e = MiriEnv::new()?;
|
||||||
let toolchain = &e.toolchain;
|
|
||||||
let config_path = path!(e.miri_dir / "rustfmt.toml");
|
let config_path = path!(e.miri_dir / "rustfmt.toml");
|
||||||
|
|
||||||
let mut cmd = cmd!(
|
// Collect each rust file in the miri repo.
|
||||||
e.sh,
|
let files = WalkDir::new(&e.miri_dir)
|
||||||
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
|
.into_iter()
|
||||||
);
|
.filter_entry(|entry| {
|
||||||
eprintln!("$ {cmd} ...");
|
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.
|
e.format_files(files, &e.toolchain[..], &config_path, &flags[..])
|
||||||
// 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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::ffi::{OsStr, OsString};
|
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 dunce::canonicalize;
|
||||||
use path_macro::path;
|
use path_macro::path;
|
||||||
use xshell::{cmd, Shell};
|
use xshell::{cmd, Shell};
|
||||||
@ -145,4 +145,48 @@ impl MiriEnv {
|
|||||||
.run()?;
|
.run()?;
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
1a1876c9790f168fb51afa335a7ba3e6fc267d75
|
4d4bb491b65c300835442f6cb4f34fc9a5685c26
|
||||||
|
@ -8,6 +8,11 @@
|
|||||||
rustc::untranslatable_diagnostic
|
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_data_structures;
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
@ -16,8 +21,6 @@ extern crate rustc_log;
|
|||||||
extern crate rustc_metadata;
|
extern crate rustc_metadata;
|
||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
use std::env::{self, VarError};
|
use std::env::{self, VarError};
|
||||||
use std::num::NonZero;
|
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`.
|
// rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`.
|
||||||
if tracing::Level::from_str(&var).is_ok() {
|
if tracing::Level::from_str(&var).is_ok() {
|
||||||
cfg.filter = Ok(format!(
|
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 {
|
} else {
|
||||||
cfg.filter = Ok(var);
|
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
|
cfg
|
||||||
@ -342,7 +341,8 @@ fn main() {
|
|||||||
// (`install_ice_hook` might change `RUST_BACKTRACE`.)
|
// (`install_ice_hook` might change `RUST_BACKTRACE`.)
|
||||||
let env_snapshot = env::vars_os().collect::<Vec<_>>();
|
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 the environment asks us to actually be rustc, then do that.
|
||||||
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
|
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
|
||||||
@ -408,17 +408,11 @@ fn main() {
|
|||||||
miri_config.check_alignment = miri::AlignmentCheck::None;
|
miri_config.check_alignment = miri::AlignmentCheck::None;
|
||||||
} else if arg == "-Zmiri-symbolic-alignment-check" {
|
} else if arg == "-Zmiri-symbolic-alignment-check" {
|
||||||
miri_config.check_alignment = miri::AlignmentCheck::Symbolic;
|
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" {
|
} else if arg == "-Zmiri-disable-abi-check" {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"WARNING: the flag `-Zmiri-disable-abi-check` is deprecated and planned to be removed.\n\
|
"WARNING: the flag `-Zmiri-disable-abi-check` no longer has any effect; \
|
||||||
If you have a use-case for it, please file an issue."
|
ABI checks cannot be disabled any more"
|
||||||
);
|
);
|
||||||
miri_config.check_abi = false;
|
|
||||||
} else if arg == "-Zmiri-disable-isolation" {
|
} else if arg == "-Zmiri-disable-isolation" {
|
||||||
if matches!(isolation_enabled, Some(true)) {
|
if matches!(isolation_enabled, Some(true)) {
|
||||||
show_error!(
|
show_error!(
|
||||||
@ -459,8 +453,6 @@ fn main() {
|
|||||||
miri_config.collect_leak_backtraces = false;
|
miri_config.collect_leak_backtraces = false;
|
||||||
} else if arg == "-Zmiri-panic-on-unsupported" {
|
} else if arg == "-Zmiri-panic-on-unsupported" {
|
||||||
miri_config.panic_on_unsupported = true;
|
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" {
|
} else if arg == "-Zmiri-strict-provenance" {
|
||||||
miri_config.provenance_mode = ProvenanceMode::Strict;
|
miri_config.provenance_mode = ProvenanceMode::Strict;
|
||||||
} else if arg == "-Zmiri-permissive-provenance" {
|
} else if arg == "-Zmiri-permissive-provenance" {
|
||||||
@ -476,10 +468,6 @@ fn main() {
|
|||||||
"scalar" => RetagFields::OnlyScalar,
|
"scalar" => RetagFields::OnlyScalar,
|
||||||
_ => show_error!("`-Zmiri-retag-fields` can only be `all`, `none`, or `scalar`"),
|
_ => 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=") {
|
} else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") {
|
||||||
if miri_config.seed.is_some() {
|
if miri_config.seed.is_some() {
|
||||||
show_error!("Cannot specify -Zmiri-seed multiple times!");
|
show_error!("Cannot specify -Zmiri-seed multiple times!");
|
||||||
|
@ -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.
|
/// 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 {
|
fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId {
|
||||||
let active_thread_id = self.active_thread;
|
assert!(id.index() < self.threads.len());
|
||||||
self.active_thread = id;
|
info!(
|
||||||
assert!(self.active_thread.index() < self.threads.len());
|
"---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------",
|
||||||
active_thread_id
|
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.
|
/// Get the id of the currently active thread.
|
||||||
@ -735,6 +738,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
|
|||||||
for (id, thread) in threads {
|
for (id, thread) in threads {
|
||||||
debug_assert_ne!(self.active_thread, id);
|
debug_assert_ne!(self.active_thread, id);
|
||||||
if thread.state == ThreadState::Enabled {
|
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;
|
self.active_thread = id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -882,7 +890,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
instance,
|
instance,
|
||||||
start_abi,
|
start_abi,
|
||||||
&[*func_arg],
|
&[*func_arg],
|
||||||
Some(&ret_place.into()),
|
Some(&ret_place),
|
||||||
StackPopCleanup::Root { cleanup: true },
|
StackPopCleanup::Root { cleanup: true },
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -94,8 +94,6 @@ pub struct MiriConfig {
|
|||||||
pub unique_is_unique: bool,
|
pub unique_is_unique: bool,
|
||||||
/// Controls alignment checking.
|
/// Controls alignment checking.
|
||||||
pub check_alignment: AlignmentCheck,
|
pub check_alignment: AlignmentCheck,
|
||||||
/// Controls function [ABI](Abi) checking.
|
|
||||||
pub check_abi: bool,
|
|
||||||
/// Action for an op requiring communication with the host.
|
/// Action for an op requiring communication with the host.
|
||||||
pub isolated_op: IsolatedOp,
|
pub isolated_op: IsolatedOp,
|
||||||
/// Determines if memory leaks should be ignored.
|
/// Determines if memory leaks should be ignored.
|
||||||
@ -162,7 +160,6 @@ impl Default for MiriConfig {
|
|||||||
borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
|
borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
|
||||||
unique_is_unique: false,
|
unique_is_unique: false,
|
||||||
check_alignment: AlignmentCheck::Int,
|
check_alignment: AlignmentCheck::Int,
|
||||||
check_abi: true,
|
|
||||||
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
|
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
|
||||||
ignore_leaks: false,
|
ignore_leaks: false,
|
||||||
forwarded_env_vars: vec![],
|
forwarded_env_vars: vec![],
|
||||||
@ -394,7 +391,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||||||
argv,
|
argv,
|
||||||
Scalar::from_u8(sigpipe).into(),
|
Scalar::from_u8(sigpipe).into(),
|
||||||
],
|
],
|
||||||
Some(&ret_place.into()),
|
Some(&ret_place),
|
||||||
StackPopCleanup::Root { cleanup: true },
|
StackPopCleanup::Root { cleanup: true },
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -403,7 +400,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||||||
entry_instance,
|
entry_instance,
|
||||||
Abi::Rust,
|
Abi::Rust,
|
||||||
&[argc.into(), argv],
|
&[argc.into(), argv],
|
||||||
Some(&ret_place.into()),
|
Some(&ret_place),
|
||||||
StackPopCleanup::Root { cleanup: true },
|
StackPopCleanup::Root { cleanup: true },
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use rustc_apfloat::ieee::{Double, Single};
|
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 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 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();
|
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!(
|
throw_ub_format!(
|
||||||
"calling a function with ABI {} using caller ABI {}",
|
"calling a function with ABI {} using caller ABI {}",
|
||||||
callee_abi.name(),
|
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 mir = this.load_mir(f.def, None)?;
|
||||||
let dest = match dest {
|
let dest = match dest {
|
||||||
Some(dest) => dest.clone(),
|
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)?;
|
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 {
|
match reject_with {
|
||||||
RejectOpWith::Abort => isolation_abort_error(op_name),
|
RejectOpWith::Abort => isolation_abort_error(op_name),
|
||||||
RejectOpWith::WarningWithoutBacktrace => {
|
RejectOpWith::WarningWithoutBacktrace => {
|
||||||
this.tcx
|
// This exists to reduce verbosity; make sure we emit the warning at most once per
|
||||||
.dcx()
|
// operation.
|
||||||
.warn(format!("{op_name} was made to return an error due to isolation"));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
RejectOpWith::Warning => {
|
RejectOpWith::Warning => {
|
||||||
@ -945,7 +956,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
|
|
||||||
/// Check that the ABI is what we expect.
|
/// Check that the ABI is what we expect.
|
||||||
fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
|
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!(
|
throw_ub_format!(
|
||||||
"calling a function with ABI {} using caller ABI {}",
|
"calling a function with ABI {} using caller ABI {}",
|
||||||
exp_abi.name(),
|
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() {
|
let ty::Float(fty) = src.layout.ty.kind() else {
|
||||||
// f32
|
bug!("float_to_int_checked: non-float input type {}", src.layout.ty)
|
||||||
ty::Float(FloatTy::F32) =>
|
};
|
||||||
|
|
||||||
|
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),
|
float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
|
||||||
// f64
|
FloatTy::F64 =>
|
||||||
ty::Float(FloatTy::F64) =>
|
|
||||||
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
|
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
|
||||||
// Nothing else
|
FloatTy::F128 => unimplemented!("f16_f128"),
|
||||||
_ =>
|
|
||||||
span_bug!(
|
|
||||||
this.cur_span(),
|
|
||||||
"attempted float-to-int conversion with non-float input type {}",
|
|
||||||
src.layout.ty,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if status.intersects(
|
if status.intersects(
|
||||||
|
@ -49,8 +49,12 @@
|
|||||||
// Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
|
// Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
|
||||||
#![recursion_limit = "256"]
|
#![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_apfloat;
|
||||||
extern crate rustc_ast;
|
extern crate rustc_ast;
|
||||||
extern crate rustc_const_eval;
|
extern crate rustc_const_eval;
|
||||||
@ -63,11 +67,8 @@ extern crate rustc_middle;
|
|||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate rustc_target;
|
extern crate rustc_target;
|
||||||
#[macro_use]
|
// Linking `rustc_driver` pulls in the required object code as the rest of the rustc crates are
|
||||||
extern crate tracing;
|
// shipped only as rmeta files.
|
||||||
|
|
||||||
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
|
|
||||||
// files.
|
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
|
|
||||||
@ -143,4 +144,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
|
|||||||
"-Zmir-keep-place-mention",
|
"-Zmir-keep-place-mention",
|
||||||
"-Zmir-opt-level=0",
|
"-Zmir-opt-level=0",
|
||||||
"-Zmir-enable-passes=-CheckAlignment",
|
"-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",
|
||||||
];
|
];
|
||||||
|
@ -462,9 +462,6 @@ pub struct MiriMachine<'mir, 'tcx> {
|
|||||||
/// Whether to enforce the validity invariant.
|
/// Whether to enforce the validity invariant.
|
||||||
pub(crate) validate: bool,
|
pub(crate) validate: bool,
|
||||||
|
|
||||||
/// Whether to enforce [ABI](Abi) of function calls.
|
|
||||||
pub(crate) enforce_abi: bool,
|
|
||||||
|
|
||||||
/// The table of file descriptors.
|
/// The table of file descriptors.
|
||||||
pub(crate) file_handler: shims::unix::FileHandler,
|
pub(crate) file_handler: shims::unix::FileHandler,
|
||||||
/// The table of directory descriptors.
|
/// The table of directory descriptors.
|
||||||
@ -643,7 +640,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
|||||||
tls: TlsData::default(),
|
tls: TlsData::default(),
|
||||||
isolated_op: config.isolated_op,
|
isolated_op: config.isolated_op,
|
||||||
validate: config.validate,
|
validate: config.validate,
|
||||||
enforce_abi: config.check_abi,
|
|
||||||
file_handler: FileHandler::new(config.mute_stdout_stderr),
|
file_handler: FileHandler::new(config.mute_stdout_stderr),
|
||||||
dir_handler: Default::default(),
|
dir_handler: Default::default(),
|
||||||
layouts,
|
layouts,
|
||||||
@ -786,7 +782,6 @@ impl VisitProvenance for MiriMachine<'_, '_> {
|
|||||||
tcx: _,
|
tcx: _,
|
||||||
isolated_op: _,
|
isolated_op: _,
|
||||||
validate: _,
|
validate: _,
|
||||||
enforce_abi: _,
|
|
||||||
clock: _,
|
clock: _,
|
||||||
layouts: _,
|
layouts: _,
|
||||||
static_roots: _,
|
static_roots: _,
|
||||||
@ -934,8 +929,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn enforce_abi(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
|
fn enforce_abi(_ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
|
||||||
ecx.machine.enforce_abi
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[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
|
// 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.
|
// writes* during this call are insta-UB.
|
||||||
let protected_place = if ecx.machine.borrow_tracker.is_some() {
|
let protected_place = if ecx.machine.borrow_tracker.is_some() {
|
||||||
ecx.protect_place(&place)?.into()
|
ecx.protect_place(place)?
|
||||||
} else {
|
} else {
|
||||||
// No borrow tracker.
|
// No borrow tracker.
|
||||||
place.clone()
|
place.clone()
|
||||||
@ -1447,13 +1442,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||||||
if ecx.machine.borrow_tracker.is_some() {
|
if ecx.machine.borrow_tracker.is_some() {
|
||||||
ecx.on_stack_pop(frame)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn after_stack_pop(
|
fn after_stack_pop(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
mut frame: Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
|
frame: Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
|
||||||
unwinding: bool,
|
unwinding: bool,
|
||||||
) -> InterpResult<'tcx, StackPopJump> {
|
) -> InterpResult<'tcx, StackPopJump> {
|
||||||
if frame.extra.is_user_relevant {
|
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.)
|
// user-relevant frame and restore that here.)
|
||||||
ecx.active_thread_mut().recompute_top_user_relevant_frame();
|
ecx.active_thread_mut().recompute_top_user_relevant_frame();
|
||||||
}
|
}
|
||||||
let timing = frame.extra.timing.take();
|
let res = {
|
||||||
let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
|
// Move `frame`` into a sub-scope so we control when it will be dropped.
|
||||||
if let Some(profiler) = ecx.machine.profiler.as_ref() {
|
let mut frame = frame;
|
||||||
profiler.finish_recording_interval_event(timing.unwrap());
|
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
|
res
|
||||||
}
|
}
|
||||||
|
@ -287,13 +287,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> {
|
let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> {
|
||||||
Ok(match x.layout.ty.kind() {
|
let ty::Float(fty) = x.layout.ty.kind() else {
|
||||||
ty::Float(FloatTy::F32) => x.to_scalar().to_f32()?.is_finite(),
|
bug!("float_finite: non-float input type {}", x.layout.ty)
|
||||||
ty::Float(FloatTy::F64) => x.to_scalar().to_f64()?.is_finite(),
|
};
|
||||||
_ => bug!(
|
Ok(match fty {
|
||||||
"`{intrinsic_name}` called with non-float input type {ty:?}",
|
FloatTy::F16 => unimplemented!("f16_f128"),
|
||||||
ty = x.layout.ty,
|
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)?) {
|
match (float_finite(&a)?, float_finite(&b)?) {
|
||||||
|
@ -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 id = this.init_once_get_id(init_once_op)?;
|
||||||
let flags = this.read_scalar(flags_op)?.to_u32()?;
|
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)?;
|
let context = this.read_pointer(context_op)?;
|
||||||
|
|
||||||
if flags != 0 {
|
if flags != 0 {
|
||||||
|
@ -183,9 +183,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.10"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
|
|
@ -10,6 +10,14 @@ note: erroneous constant encountered
|
|||||||
LL | let _x = UNALIGNED_READ;
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
@ -10,6 +10,14 @@ note: erroneous constant encountered
|
|||||||
LL | println!("{}", FOO);
|
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
|
note: erroneous constant encountered
|
||||||
--> $DIR/erroneous_const2.rs:LL:CC
|
--> $DIR/erroneous_const2.rs:LL:CC
|
||||||
|
|
|
|
||||||
|
@ -19,7 +19,6 @@ fn main() {
|
|||||||
after_call = {
|
after_call = {
|
||||||
Return()
|
Return()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ LL | | let _unit: ();
|
|||||||
LL | | {
|
LL | | {
|
||||||
LL | | let non_copy = S(42);
|
LL | | let non_copy = S(42);
|
||||||
... |
|
... |
|
||||||
LL | |
|
LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
help: <TAG> is this argument
|
help: <TAG> is this argument
|
||||||
|
@ -16,7 +16,7 @@ LL | | let _unit: ();
|
|||||||
LL | | {
|
LL | | {
|
||||||
LL | | let non_copy = S(42);
|
LL | | let non_copy = S(42);
|
||||||
... |
|
... |
|
||||||
LL | |
|
LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
help: the protected tag <TAG> was created here, in the initial state Reserved
|
help: the protected tag <TAG> was created here, in the initial state Reserved
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
//@compile-flags: -Zmiri-disable-abi-check
|
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -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:
|
thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC:
|
||||||
explicit panic
|
explicit panic
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
|
|
||||||
//! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
|
//! 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() {
|
extern "C-unwind" fn unwind() {
|
||||||
panic!();
|
panic!();
|
||||||
|
@ -219,6 +219,7 @@ fn wait_wake_bitset() {
|
|||||||
t.join().unwrap();
|
t.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crucial test which relies on the SeqCst fences in futex wait/wake.
|
||||||
fn concurrent_wait_wake() {
|
fn concurrent_wait_wake() {
|
||||||
const FREE: i32 = 0;
|
const FREE: i32 = 0;
|
||||||
const HELD: i32 = 1;
|
const HELD: i32 = 1;
|
||||||
|
@ -7,6 +7,10 @@ use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
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.
|
// Check if Rust barriers are working.
|
||||||
|
|
||||||
/// This test is taken from the Rust documentation.
|
/// 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();
|
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(10)).unwrap();
|
||||||
assert!(timeout.timed_out());
|
assert!(timeout.timed_out());
|
||||||
let elapsed_time = now.elapsed().as_millis();
|
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
|
/// 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();
|
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());
|
assert!(!timeout.timed_out());
|
||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
@ -213,20 +218,21 @@ fn check_once() {
|
|||||||
fn park_timeout() {
|
fn park_timeout() {
|
||||||
let start = Instant::now();
|
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
|
// Normally, waiting in park/park_timeout may spuriously wake up early, but we
|
||||||
// know Miri's timed synchronization primitives do not do that.
|
// 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();
|
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() {
|
fn park_unpark() {
|
||||||
let t1 = thread::current();
|
let t1 = thread::current();
|
||||||
let t2 = thread::spawn(move || {
|
let t2 = thread::spawn(move || {
|
||||||
thread::park();
|
thread::park();
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(10));
|
||||||
t1.unpark();
|
t1.unpark();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -236,10 +242,11 @@ fn park_unpark() {
|
|||||||
thread::park();
|
thread::park();
|
||||||
// Normally, waiting in park/park_timeout may spuriously wake up early, but we
|
// Normally, waiting in park/park_timeout may spuriously wake up early, but we
|
||||||
// know Miri's timed synchronization primitives do not do that.
|
// 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();
|
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();
|
t2.join().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -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!(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.
|
|
@ -295,7 +295,7 @@ fn test_canonicalize() {
|
|||||||
drop(File::create(&path).unwrap());
|
drop(File::create(&path).unwrap());
|
||||||
|
|
||||||
let p = canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).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();
|
remove_dir_all(&dir_path).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -79,13 +79,6 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
|
|||||||
program.args.push(flag);
|
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 {
|
let mut config = Config {
|
||||||
target: Some(target.to_owned()),
|
target: Some(target.to_owned()),
|
||||||
stderr_filters: STDERR.clone(),
|
stderr_filters: STDERR.clone(),
|
||||||
@ -116,9 +109,21 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
|
|||||||
config
|
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);
|
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.
|
// Handle command-line arguments.
|
||||||
let args = ui_test::Args::test()?;
|
let args = ui_test::Args::test()?;
|
||||||
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
|
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
|
||||||
@ -211,7 +216,13 @@ enum Dependencies {
|
|||||||
|
|
||||||
use 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}");
|
let msg = format!("## Running ui tests in {path} against miri for {target}");
|
||||||
eprintln!("{}", msg.green().bold());
|
eprintln!("{}", msg.green().bold());
|
||||||
|
|
||||||
@ -219,7 +230,7 @@ fn ui(mode: Mode, path: &str, target: &str, with_dependencies: Dependencies) ->
|
|||||||
WithDependencies => true,
|
WithDependencies => true,
|
||||||
WithoutDependencies => false,
|
WithoutDependencies => false,
|
||||||
};
|
};
|
||||||
run_tests(mode, path, target, with_dependencies)
|
run_tests(mode, path, target, with_dependencies, tmpdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_target() -> String {
|
fn get_target() -> String {
|
||||||
@ -230,6 +241,7 @@ fn main() -> Result<()> {
|
|||||||
ui_test::color_eyre::install()?;
|
ui_test::color_eyre::install()?;
|
||||||
|
|
||||||
let target = get_target();
|
let target = get_target();
|
||||||
|
let tmpdir = tempfile::Builder::new().prefix("miri-uitest-").tempdir()?;
|
||||||
|
|
||||||
let mut args = std::env::args_os();
|
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", &target, WithoutDependencies, tmpdir.path())?;
|
||||||
ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies)?;
|
ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies, tmpdir.path())?;
|
||||||
ui(Mode::Panic, "tests/panic", &target, WithDependencies)?;
|
ui(Mode::Panic, "tests/panic", &target, WithDependencies, tmpdir.path())?;
|
||||||
ui(
|
ui(
|
||||||
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
||||||
"tests/fail",
|
"tests/fail",
|
||||||
&target,
|
&target,
|
||||||
WithoutDependencies,
|
WithoutDependencies,
|
||||||
|
tmpdir.path(),
|
||||||
)?;
|
)?;
|
||||||
ui(
|
ui(
|
||||||
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
||||||
"tests/fail-dep",
|
"tests/fail-dep",
|
||||||
&target,
|
&target,
|
||||||
WithDependencies,
|
WithDependencies,
|
||||||
|
tmpdir.path(),
|
||||||
)?;
|
)?;
|
||||||
if cfg!(target_os = "linux") {
|
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(
|
ui(
|
||||||
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
||||||
"tests/extern-so/fail",
|
"tests/extern-so/fail",
|
||||||
&target,
|
&target,
|
||||||
WithoutDependencies,
|
WithoutDependencies,
|
||||||
|
tmpdir.path(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user