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

Miri subtree update

r? `@ghost`
This commit is contained in:
bors 2024-03-25 18:20:03 +00:00
commit 35936c4839
14 changed files with 141 additions and 27 deletions

View File

@ -30,11 +30,16 @@ jobs:
host_target: i686-pc-windows-msvc host_target: i686-pc-windows-msvc
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
RUST_BACKTRACE: 1
HOST_TARGET: ${{ matrix.host_target }} HOST_TARGET: ${{ matrix.host_target }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Show Rust version (stable toolchain)
run: |
rustup show
rustc -Vv
cargo -V
# Cache the global cargo directory, but NOT the local `target` directory which # Cache the global cargo directory, but NOT the local `target` directory which
# we cannot reuse anyway when the nightly changes (and it grows quite large # we cannot reuse anyway when the nightly changes (and it grows quite large
# over time). # over time).
@ -58,7 +63,7 @@ jobs:
if: ${{ steps.cache.outputs.cache-hit != 'true' }} if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: cargo install -f rustup-toolchain-install-master run: cargo install -f rustup-toolchain-install-master
- name: Install "master" toolchain - name: Install miri toolchain
run: | run: |
if [[ ${{ github.event_name }} == 'schedule' ]]; then if [[ ${{ github.event_name }} == 'schedule' ]]; then
echo "Building against latest rustc git version" echo "Building against latest rustc git version"
@ -66,13 +71,13 @@ jobs:
fi fi
./miri toolchain --host ${{ matrix.host_target }} ./miri toolchain --host ${{ matrix.host_target }}
- name: Show Rust version - name: Show Rust version (miri toolchain)
run: | run: |
rustup show rustup show
rustc -Vv rustc -Vv
cargo -V cargo -V
- name: Test - name: Test Miri
run: ./ci/ci.sh run: ./ci/ci.sh
style: style:

View File

@ -64,19 +64,22 @@ For example, you can (cross-)run the driver on a particular file by doing
./miri run tests/pass/hello.rs --target i686-unknown-linux-gnu ./miri run tests/pass/hello.rs --target i686-unknown-linux-gnu
``` ```
and you can (cross-)run the entire test suite using: Tests in ``pass-dep`` need to be run using ``./miri run --dep <filename>``.
For example:
```sh
./miri run --dep tests/pass-dep/shims/libc-fs.rs
```
You can (cross-)run the entire test suite using:
``` ```
./miri test ./miri test
MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test
``` ```
If your target doesn't support libstd that should usually just work. However, if you are using a
custom target file, you might have to set `MIRI_NO_STD=1`.
`./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the
base directory, e.g. `./miri test fail` will run all compile-fail tests). These filters are passed base directory, e.g. `./miri test fail` will run all compile-fail tests). These filters are passed
to `cargo test`, so for multiple filers you need to use `./miri test -- FILTER1 FILTER2`. to `cargo test`, so for multiple filters you need to use `./miri test -- FILTER1 FILTER2`.
#### Fine grained logging #### Fine grained logging
@ -178,6 +181,7 @@ to `.vscode/settings.json` in your local Miri clone:
"cargo", "cargo",
"clippy", // make this `check` when working with a locally built rustc "clippy", // make this `check` when working with a locally built rustc
"--message-format=json", "--message-format=json",
"--all-targets",
], ],
// Contrary to what the name suggests, this also affects proc macros. // Contrary to what the name suggests, this also affects proc macros.
"rust-analyzer.cargo.buildScripts.overrideCommand": [ "rust-analyzer.cargo.buildScripts.overrideCommand": [
@ -187,6 +191,7 @@ to `.vscode/settings.json` in your local Miri clone:
"cargo", "cargo",
"check", "check",
"--message-format=json", "--message-format=json",
"--all-targets",
], ],
} }
``` ```

View File

@ -11,10 +11,18 @@
use crate::phases::*; use crate::phases::*;
/// Returns `true` if our flags look like they may be for rustdoc, i.e., this is cargo calling us to
/// be rustdoc. It's hard to be sure as cargo does not have a RUSTDOC_WRAPPER or an env var that
/// would let us get a clear signal.
fn looks_like_rustdoc() -> bool {
// The `--test-run-directory` flag only exists for rustdoc and cargo always passes it. Perfect!
env::args().any(|arg| arg == "--test-run-directory")
}
fn main() { fn main() {
// Rustc does not support non-UTF-8 arguments so we make no attempt either. // Rustc does not support non-UTF-8 arguments so we make no attempt either.
// (We do support non-UTF-8 environment variables though.) // (We do support non-UTF-8 environment variables though.)
let mut args = std::env::args(); let mut args = env::args();
// Skip binary name. // Skip binary name.
args.next().unwrap(); args.next().unwrap();
@ -91,10 +99,16 @@ fn main() {
// (see https://github.com/rust-lang/cargo/issues/10886). // (see https://github.com/rust-lang/cargo/issues/10886).
phase_rustc(args, RustcPhase::Build) phase_rustc(args, RustcPhase::Build)
} }
_ => { _ if looks_like_rustdoc() => {
// Everything else must be rustdoc. But we need to get `first` "back onto the iterator", // This is probably rustdoc. But we need to get `first` "back onto the iterator",
// it is some part of the rustdoc invocation. // it is some part of the rustdoc invocation.
phase_rustdoc(iter::once(first).chain(args)); phase_rustdoc(iter::once(first).chain(args));
} }
_ => {
show_error!(
"`cargo-miri` failed to recognize which phase of the build process this is, please report a bug.\nThe command-line arguments were: {:#?}",
Vec::from_iter(env::args()),
);
}
} }
} }

View File

@ -620,7 +620,7 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
// The `--test-builder` and `--runtool` arguments are unstable rustdoc features, // The `--test-builder` and `--runtool` arguments are unstable rustdoc features,
// which are disabled by default. We first need to enable them explicitly: // which are disabled by default. We first need to enable them explicitly:
cmd.arg("-Z").arg("unstable-options"); cmd.arg("-Zunstable-options");
// rustdoc needs to know the right sysroot. // rustdoc needs to know the right sysroot.
cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap());

View File

@ -13,6 +13,15 @@ function endgroup {
begingroup "Building Miri" begingroup "Building Miri"
# Special Windows hacks
if [ "$HOST_TARGET" = i686-pc-windows-msvc ]; then
# The $BASH variable is `/bin/bash` here, but that path does not actually work. There are some
# hacks in place somewhere to try to paper over this, but the hacks dont work either (see
# <https://github.com/rust-lang/miri/pull/3402>). So we hard-code the correct location for Github
# CI instead.
BASH="C:/Program Files/Git/usr/bin/bash"
fi
# Determine configuration for installed build # Determine configuration for installed build
echo "Installing release version of Miri" echo "Installing release version of Miri"
export RUSTFLAGS="-D warnings" export RUSTFLAGS="-D warnings"
@ -58,12 +67,13 @@ function run_tests {
MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic}
# Also run some many-seeds tests. 64 seeds means this takes around a minute per test. # Also run some many-seeds tests. 64 seeds means this takes around a minute per test.
# (Need to invoke via explicit `bash -c` for Windows.)
for FILE in tests/many-seeds/*.rs; do for FILE in tests/many-seeds/*.rs; do
MIRI_SEEDS=64 ./miri many-seeds ./miri run "$FILE" MIRI_SEEDS=64 ./miri many-seeds "$BASH" -c "./miri run '$FILE'"
done done
# Check that the benchmarks build and run, but without actually benchmarking. # Check that the benchmarks build and run, but without actually benchmarking.
HYPERFINE="bash -c" ./miri bench HYPERFINE="'$BASH' -c" ./miri bench
fi fi
## test-cargo-miri ## test-cargo-miri

View File

@ -3,5 +3,5 @@ set -e
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through # Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
# rustup (that sets it's own environmental variables), which is undesirable. # rustup (that sets it's own environmental variables), which is undesirable.
MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target
cargo build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml
"$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@" "$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@"

View File

@ -178,7 +178,7 @@ fn toolchain(flags: Vec<OsString>) -> Result<()> {
.context("Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'")?; .context("Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'")?;
let sh = Shell::new()?; let sh = Shell::new()?;
sh.change_dir(miri_dir()?); sh.change_dir(miri_dir()?);
let new_commit = Some(sh.read_file("rust-version")?.trim().to_owned()); let new_commit = sh.read_file("rust-version")?.trim().to_owned();
let current_commit = { let current_commit = {
let rustc_info = cmd!(sh, "rustc +miri --version -v").read(); let rustc_info = cmd!(sh, "rustc +miri --version -v").read();
if rustc_info.is_err() { if rustc_info.is_err() {
@ -193,7 +193,7 @@ fn toolchain(flags: Vec<OsString>) -> Result<()> {
} }
}; };
// Check if we already are at that commit. // Check if we already are at that commit.
if current_commit == new_commit { if current_commit.as_ref() == Some(&new_commit) {
if active_toolchain()? != "miri" { if active_toolchain()? != "miri" {
cmd!(sh, "rustup override set miri").run()?; cmd!(sh, "rustup override set miri").run()?;
} }
@ -202,7 +202,7 @@ fn toolchain(flags: Vec<OsString>) -> Result<()> {
// Install and setup new toolchain. // Install and setup new toolchain.
cmd!(sh, "rustup toolchain uninstall miri").run()?; cmd!(sh, "rustup toolchain uninstall miri").run()?;
cmd!(sh, "rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy {flags...} -- {new_commit...}").run()?; cmd!(sh, "rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy {flags...} -- {new_commit}").run()?;
cmd!(sh, "rustup override set miri").run()?; cmd!(sh, "rustup override set miri").run()?;
// Cleanup. // Cleanup.
cmd!(sh, "cargo clean").run()?; cmd!(sh, "cargo clean").run()?;
@ -380,9 +380,9 @@ fn many_seeds(command: Vec<OsString>) -> Result<()> {
.env("MIRIFLAGS", miriflags) .env("MIRIFLAGS", miriflags)
.quiet() .quiet()
.run(); .run();
if status.is_err() { if let Err(err) = status {
println!("Failing seed: {seed}"); println!("Failing seed: {seed}");
break; return Err(err.into());
} }
} }
Ok(()) Ok(())

View File

@ -5,7 +5,7 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
:: If any other steps are added, the "|| exit /b" must be appended to early :: If any other steps are added, the "|| exit /b" must be appended to early
:: return from the script. If not, it will continue execution. :: return from the script. If not, it will continue execution.
cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml || exit /b cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml || exit /b
:: Forwards all arguments to this file to the executable. :: Forwards all arguments to this file to the executable.
:: We invoke the binary directly to avoid going through rustup, which would set some extra :: We invoke the binary directly to avoid going through rustup, which would set some extra

View File

@ -1 +1 @@
c3b05c6e5b5b59613350b8c2875b0add67ed74df cb7c63606e53715f94f3ba04d38e50772e4cd23d

View File

@ -276,7 +276,7 @@ fn run_compiler(
// If no `--sysroot` is given, the `MIRI_SYSROOT` env var is consulted to find where // If no `--sysroot` is given, the `MIRI_SYSROOT` env var is consulted to find where
// that sysroot lives, and that is passed to rustc. // that sysroot lives, and that is passed to rustc.
let sysroot_flag = "--sysroot"; let sysroot_flag = "--sysroot";
if !args.iter().any(|e| e == sysroot_flag) { if !args.iter().any(|e| e.starts_with(sysroot_flag)) {
// Using the built-in default here would be plain wrong, so we *require* // Using the built-in default here would be plain wrong, so we *require*
// the env var to make sure things make sense. // the env var to make sure things make sense.
let miri_sysroot = env::var("MIRI_SYSROOT").unwrap_or_else(|_| { let miri_sysroot = env::var("MIRI_SYSROOT").unwrap_or_else(|_| {

View File

@ -2,6 +2,12 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "anyhow"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -24,6 +30,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
name = "cargo-miri-test" name = "cargo-miri-test"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"autocfg", "autocfg",
"byteorder 0.5.3", "byteorder 0.5.3",
"byteorder 1.4.3", "byteorder 1.4.3",

View File

@ -22,6 +22,9 @@ issue_rust_86261 = { path = "issue-rust-86261" }
byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming
# Not actually used, but exercises some unique code path (`--extern` .so file). # Not actually used, but exercises some unique code path (`--extern` .so file).
serde_derive = "1.0.185" serde_derive = "1.0.185"
# Not actually used, but uses a custom build probe so let's make sure that works.
# (Ideally we'd check if the probe was successful, but that's not easily possible.)
anyhow = "1.0"
[build-dependencies] [build-dependencies]
autocfg = "1" autocfg = "1"

View File

@ -16,6 +16,10 @@
fn main() { fn main() {
test_dup_stdout_stderr(); test_dup_stdout_stderr();
test_canonicalize_too_long(); test_canonicalize_too_long();
test_rename();
test_ftruncate::<libc::off_t>(libc::ftruncate);
#[cfg(target_os = "linux")]
test_ftruncate::<libc::off64_t>(libc::ftruncate64);
test_readlink(); test_readlink();
test_file_open_unix_allow_two_args(); test_file_open_unix_allow_two_args();
test_file_open_unix_needs_three_args(); test_file_open_unix_needs_three_args();
@ -133,6 +137,65 @@ fn test_readlink() {
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
} }
fn test_rename() {
let path1 = prepare("miri_test_libc_fs_source.txt");
let path2 = prepare("miri_test_libc_fs_rename_destination.txt");
let file = File::create(&path1).unwrap();
drop(file);
let c_path1 = CString::new(path1.as_os_str().as_bytes()).expect("CString::new failed");
let c_path2 = CString::new(path2.as_os_str().as_bytes()).expect("CString::new failed");
// Renaming should succeed
unsafe { libc::rename(c_path1.as_ptr(), c_path2.as_ptr()) };
// Check that old file path isn't present
assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
// Check that the file has moved successfully
assert!(path2.metadata().unwrap().is_file());
// Renaming a nonexistent file should fail
let res = unsafe { libc::rename(c_path1.as_ptr(), c_path2.as_ptr()) };
assert_eq!(res, -1);
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
remove_file(&path2).unwrap();
}
fn test_ftruncate<T: From<i32>>(
ftruncate: unsafe extern "C" fn(fd: libc::c_int, length: T) -> libc::c_int,
) {
// libc::off_t is i32 in target i686-unknown-linux-gnu
// https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html
let bytes = b"hello";
let path = prepare("miri_test_libc_fs_ftruncate.txt");
let mut file = File::create(&path).unwrap();
file.write(bytes).unwrap();
file.sync_all().unwrap();
assert_eq!(file.metadata().unwrap().len(), 5);
let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
let fd = unsafe { libc::open(c_path.as_ptr(), libc::O_RDWR) };
// Truncate to a bigger size
let mut res = unsafe { ftruncate(fd, T::from(10)) };
assert_eq!(res, 0);
assert_eq!(file.metadata().unwrap().len(), 10);
// Write after truncate
file.write(b"dup").unwrap();
file.sync_all().unwrap();
assert_eq!(file.metadata().unwrap().len(), 10);
// Truncate to smaller size
res = unsafe { ftruncate(fd, T::from(2)) };
assert_eq!(res, 0);
assert_eq!(file.metadata().unwrap().len(), 2);
remove_file(&path).unwrap();
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn test_o_tmpfile_flag() { fn test_o_tmpfile_flag() {
use std::fs::{create_dir, OpenOptions}; use std::fs::{create_dir, OpenOptions};

View File

@ -4,8 +4,11 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::{env, process::Command}; use std::{env, process::Command};
use ui_test::{color_eyre::Result, Config, Match, Mode, OutputConflictHandling}; use ui_test::color_eyre::eyre::{Context, Result};
use ui_test::{status_emitter, CommandBuilder, Format, RustfixMode}; use ui_test::{
status_emitter, CommandBuilder, Config, Format, Match, Mode, OutputConflictHandling,
RustfixMode,
};
fn miri_path() -> PathBuf { fn miri_path() -> PathBuf {
PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri")))
@ -124,6 +127,9 @@ fn run_tests(
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). // 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()))); config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));
// If a test ICEs, we want to see a backtrace.
config.program.envs.push(("RUST_BACKTRACE".into(), Some("1".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");
@ -223,7 +229,7 @@ fn ui(
with_dependencies: Dependencies, with_dependencies: Dependencies,
tmpdir: &Path, tmpdir: &Path,
) -> Result<()> { ) -> Result<()> {
let msg = format!("## Running ui tests in {path} against miri for {target}"); let msg = format!("## Running ui tests in {path} for {target}");
eprintln!("{}", msg.green().bold()); eprintln!("{}", msg.green().bold());
let with_dependencies = match with_dependencies { let with_dependencies = match with_dependencies {
@ -231,6 +237,7 @@ fn ui(
WithoutDependencies => false, WithoutDependencies => false,
}; };
run_tests(mode, path, target, with_dependencies, tmpdir) run_tests(mode, path, target, with_dependencies, tmpdir)
.with_context(|| format!("ui tests in {path} for {target} failed"))
} }
fn get_target() -> String { fn get_target() -> String {