diff --git a/Cargo.lock b/Cargo.lock index 9f64aa44314db..a23c1f88e5aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,18 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "bstr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + [[package]] name = "build-manifest" version = "0.1.0" @@ -919,25 +931,11 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -967,16 +965,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -1260,6 +1248,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "filetime" version = "0.2.14" @@ -1584,7 +1581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", - "bstr", + "bstr 0.2.17", "fnv", "log", "regex", @@ -2341,9 +2338,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opener" @@ -2351,7 +2348,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" dependencies = [ - "bstr", + "bstr 0.2.17", "winapi", ] @@ -3008,9 +3005,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f3689b6c560d6a3a17fcbe54204cd870b4fcf46342d60de16715b660d2c92" +checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd" dependencies = [ "anyhow", "rustc_version", @@ -3098,9 +3095,10 @@ dependencies = [ name = "rustc-workspace-hack" version = "1.0.0" dependencies = [ - "bstr", + "bstr 0.2.17", "clap 3.2.20", "libz-sys", + "rand 0.8.5", "regex", "serde_json", "syn", @@ -4767,13 +4765,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand 0.8.5", "redox_syscall", "remove_dir_all", "winapi", @@ -5119,20 +5117,22 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "ui_test" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" +checksum = "bf4559da3fe6b481f8674a29379677cb9606cd6f75fc254a2c9834c55638503d" dependencies = [ + "bstr 1.0.1", "cargo_metadata 0.15.0", "color-eyre", "colored", - "crossbeam", + "crossbeam-channel", "diff", "lazy_static", "regex", "rustc_version", "serde", "serde_json", + "tempfile", ] [[package]] diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 607ffe0cc59fe..138a69974e144 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -67,10 +67,10 @@ jobs: shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then - ./miri toolchain HEAD --host ${{ matrix.host_target }} - else - ./miri toolchain "" --host ${{ matrix.host_target }} + echo "Building against latest rustc git version" + git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version fi + ./miri toolchain --host ${{ matrix.host_target }} - name: Show Rust version run: | diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 5c41547616ec6..5f46e2af0f9c3 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -150,7 +150,8 @@ is set the `MIRI_LIB_SRC` environment variable to the `library` folder 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 manually (on Linux, `rm -rf ~/.cache/miri`; -and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`). +on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`; +and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`). ### Benchmarking @@ -208,23 +209,6 @@ We described above the simplest way to get a working build environment for Miri, which is to use the version of rustc indicated by `rustc-version`. But sometimes, that is not enough. -### Updating `rustc-version` - -The `rustc-version` file is regularly updated to keep Miri close to the latest -version of rustc. Usually, new contributors do not have to worry about this. But -sometimes a newer rustc is needed for a patch, and sometimes Miri needs fixing -for changes in rustc. In both cases, `rustc-version` needs updating. - -To update the `rustc-version` file and install the latest rustc, you can run: -``` -./miri toolchain HEAD -``` - -Now edit Miri until `./miri test` passes, and submit a PR. Generally, it is -preferred to separate updating `rustc-version` and doing what it takes to get -Miri working again, from implementing new features that rely on the updated -rustc. This avoids blocking all Miri development on landing a big PR. - ### Building Miri with a locally built rustc [building Miri with a locally built rustc]: #building-miri-with-a-locally-built-rustc @@ -282,13 +266,13 @@ With this, you should now have a working development setup! See ## Advanced topic: Syncing with the rustc repo We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit -changes between the rustc and Miri repositories. For now, a fork of josh needs to be built -from source. This downloads and runs josh: +changes between the rustc and Miri repositories. For now, the latest git version +of josh needs to be built from source. This downloads and runs josh: ```sh -git clone https://github.com/RalfJung/josh +git clone https://github.com/josh-project/josh cd josh -cargo run --release -p josh-proxy -- --local=$(pwd)/local --remote=https://github.com --no-background +cargo run --release -p josh-proxy -- --local=local --remote=https://github.com --no-background ``` ### Importing changes from the rustc repo @@ -298,9 +282,10 @@ We assume we start on an up-to-date master branch in the Miri repo. ```sh # Fetch and merge rustc side of the history. Takes ca 5 min the first time. +# This will also update the 'rustc-version' file. ./miri rustc-pull -# Update toolchain reference and apply formatting. -./miri toolchain HEAD && ./miri fmt +# Update local toolchain and apply formatting. +./miri toolchain && ./miri fmt git commit -am "rustup" ``` diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 343cf0eaba251..3c890df08cc26 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -64,6 +64,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bstr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + [[package]] name = "camino" version = "1.1.1" @@ -145,20 +157,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -169,41 +167,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "once_cell", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.11" @@ -243,6 +206,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "getrandom" version = "0.2.7" @@ -385,15 +357,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.5.4" @@ -560,12 +523,27 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + [[package]] name = "regex-syntax" version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -677,6 +655,20 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -739,20 +731,22 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" +checksum = "bf4559da3fe6b481f8674a29379677cb9606cd6f75fc254a2c9834c55638503d" dependencies = [ + "bstr", "cargo_metadata", "color-eyre", "colored", - "crossbeam", + "crossbeam-channel", "diff", "lazy_static", "regex", "rustc_version", "serde", "serde_json", + "tempfile", ] [[package]] diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 02485dab74c5b..65ef92e21d6b1 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -40,7 +40,7 @@ libloading = "0.7" [dev-dependencies] colored = "2" -ui_test = "0.3.1" +ui_test = "0.4" rustc_version = "0.4" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 1185525f6865c..e9738cbc515ff 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -432,7 +432,9 @@ Moreover, Miri recognizes some environment variables: 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 manually (on Linux, `rm -rf ~/.cache/miri`). + cache 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 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 @@ -568,6 +570,15 @@ extern "Rust" { /// program) the contents of a section of program memory, as bytes. Bytes /// written using this function will emerge from the interpreter's stderr. fn miri_write_to_stderr(bytes: &[u8]); + + /// Miri-provided extern function to allocate memory from the interpreter. + /// + /// This is useful when no fundamental way of allocating memory is + /// available, e.g. when using `no_std` + `alloc`. + fn miri_alloc(size: usize, align: usize) -> *mut u8; + + /// Miri-provided extern function to deallocate memory. + fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); } ``` diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index 2beb6e1f1a463..3e5d388668b3e 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -175,9 +175,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f3689b6c560d6a3a17fcbe54204cd870b4fcf46342d60de16715b660d2c92" +checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd" dependencies = [ "anyhow", "rustc_version", diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index fcdd122747da5..ce8457469e7cf 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "4" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.15.0" -rustc-build-sysroot = "0.3.3" +rustc-build-sysroot = "0.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index f3841a6140839..9c179e82ba137 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -5,7 +5,7 @@ use std::ffi::OsStr; use std::path::PathBuf; use std::process::{self, Command}; -use rustc_build_sysroot::{BuildMode, Sysroot, SysrootConfig}; +use rustc_build_sysroot::{BuildMode, SysrootBuilder, SysrootConfig}; use rustc_version::VersionMeta; use crate::util::*; @@ -70,9 +70,11 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() { SysrootConfig::NoStd } else { - SysrootConfig::WithStd { std_features: &["panic_unwind", "backtrace"] } + SysrootConfig::WithStd { + std_features: ["panic_unwind", "backtrace"].into_iter().map(Into::into).collect(), + } }; - let cargo_cmd = || { + let cargo_cmd = { let mut command = cargo(); // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, @@ -106,13 +108,14 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); } - // Disable debug assertions in the standard library -- Miri is already slow enough. - // But keep the overflow checks, they are cheap. This completely overwrites flags - // the user might have set, which is consistent with normal `cargo build` that does - // not apply `RUSTFLAGS` to the sysroot either. - let rustflags = vec!["-Cdebug-assertions=off".into(), "-Coverflow-checks=on".into()]; - (command, rustflags) + + command }; + // Disable debug assertions in the standard library -- Miri is already slow enough. + // But keep the overflow checks, they are cheap. This completely overwrites flags + // the user might have set, which is consistent with normal `cargo build` that does + // not apply `RUSTFLAGS` to the sysroot either. + let rustflags = &["-Cdebug-assertions=off", "-Coverflow-checks=on"]; // Make sure all target-level Miri invocations know their sysroot. std::env::set_var("MIRI_SYSROOT", &sysroot_dir); @@ -124,8 +127,13 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta // We want to be quiet, but still let the user know that something is happening. eprint!("Preparing a sysroot for Miri (target: {target})... "); } - Sysroot::new(&sysroot_dir, target) - .build_from_source(&rust_src, BuildMode::Check, sysroot_config, rustc_version, cargo_cmd) + SysrootBuilder::new(&sysroot_dir, target) + .build_mode(BuildMode::Check) + .rustc_version(rustc_version.clone()) + .sysroot_config(sysroot_config) + .rustflags(rustflags) + .cargo(cargo_cmd) + .build_from_source(&rust_src) .unwrap_or_else(|_| { if only_setup { show_error!("failed to build sysroot, see error details above") diff --git a/src/tools/miri/miri b/src/tools/miri/miri index f0986bfb1cdbe..b09897c294cd1 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -42,21 +42,21 @@ many different seeds. Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. can explicitly list the benchmarks to run; by default, all of them are run. +./miri toolchain : +Update and activate the rustup toolchain 'miri' to the commit given in the +`rust-version` file. +`rustup-toolchain-install-master` must be installed for this to work. Any extra +flags are passed to `rustup-toolchain-install-master`. + ./miri rustc-pull: -Pull and merge Miri changes from the rustc repo. +Pull and merge Miri changes from the rustc repo. The fetched commit is stored in +the `rust-version` file, so the next `./miri toolchain` will install the rustc +we just pulled. ./miri rustc-push : -Push Miri changes back to the rustc repo. This will update the 'master' branch -in the Rust fork of the given user to upstream. It will also pull a copy of the -rustc history into the Miri repo, unless you set the RUSTC_GIT env var to an -existing clone of the rustc repo. - -./miri toolchain : -Update and activate the rustup toolchain 'miri'. If no commit is given, updates -to the commit given in the `rust-version` file. If the commit is `HEAD`, updates -to the latest upstream rustc commit. -`rustup-toolchain-install-master` must be installed for this to work. Any extra -flags are passed to `rustup-toolchain-install-master`. +Push Miri changes back to the rustc repo. This will pull a copy of the rustc +history into the Miri repo, unless you set the RUSTC_GIT env var to an existing +clone of the rustc repo. ENVIRONMENT VARIABLES @@ -78,7 +78,7 @@ shift # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") # Used for rustc syncs. -JOSH_FILTER=":at_commit=75dd959a3a40eb5b4574f8d2e23aa6efbeb33573[:prefix=src/tools/miri]:/src/tools/miri" +JOSH_FILTER=":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri" # Needed for `./miri bench`. TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) @@ -86,21 +86,12 @@ TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' case "$COMMAND" in toolchain) cd "$MIRIDIR" + NEW_COMMIT=$(cat rust-version) # Make sure rustup-toolchain-install-master is installed. if ! which rustup-toolchain-install-master >/dev/null; then echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'" exit 1 fi - # Determine new commit. - if [[ "$1" == "" ]]; then - NEW_COMMIT=$(cat rust-version) - elif [[ "$1" == "HEAD" ]]; then - NEW_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) - else - NEW_COMMIT="$1" - fi - echo "$NEW_COMMIT" > rust-version - shift || true # don't fail if shifting fails because no commit was given # Check if we already are at that commit. CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | grep "^commit-hash: " | cut -d " " -f 2) if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then @@ -122,8 +113,18 @@ toolchain) ;; rustc-pull) cd "$MIRIDIR" + FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) + # We can't pull from a commit with josh + # (https://github.com/josh-project/josh/issues/1034), so we just hope that + # nothing gets merged into rustc *during* this pull. git fetch http://localhost:8000/rust-lang/rust.git$JOSH_FILTER.git master + # Just verify that `master` didn't move. + if [[ $FETCH_COMMIT != $(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) ]]; then + echo "Looks like something got merged into Rust *while we were pulling*. Aborting. Please try again." + fi + echo "$FETCH_COMMIT" > rust-version # do this *before* merging as merging will fail in case of conflicts git merge FETCH_HEAD --no-ff -m "Merge from rustc" + git commit rust-version --amend -m "Merge from rustc" exit 0 ;; rustc-push) @@ -145,19 +146,21 @@ rustc-push) fi cd "$MIRIDIR" fi - # Prepare the branches. For reliable pushing we need to push to a non-existent branch - # and set `-o base` to a branch that holds current rustc master. - echo "Preparing $USER/rust..." - if git fetch https://github.com/$USER/rust $BRANCH &>/dev/null; then - echo "The '$BRANCH' seems to already exist in $USER/rust. Please delete it and try again." + # Prepare the branch. Pushing works much better if we use as base exactly + # the commit that we pulled from last time, so we use the `rust-version` + # file as a good approximation of that. + BASE=$(cat "$MIRIDIR/rust-version") + echo "Preparing $USER/rust (base: $BASE)..." + if git fetch "https://github.com/$USER/rust" "$BRANCH" &>/dev/null; then + echo "The branch '$BRANCH' seems to already exist in 'https://github.com/$USER/rust'. Please delete it and try again." exit 1 fi - git fetch https://github.com/rust-lang/rust master - git push https://github.com/$USER/rust FETCH_HEAD:master + git fetch https://github.com/rust-lang/rust $BASE + git push https://github.com/$USER/rust $BASE:refs/heads/$BRANCH -f # Do the actual push. cd "$MIRIDIR" echo "Pushing Miri changes..." - git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH -o base=master + git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH exit 0 ;; many-seeds) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 13492d183c999..746fcb2e183c6 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -b03502b35d111bef0399a66ab3cc765f0802e8ba +101e1822c3e54e63996c8aaa014d55716f3937eb diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index d0fc349f1acc3..b0f766462127f 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -49,7 +49,7 @@ use std::{ use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::{mir, ty::layout::TyAndLayout}; +use rustc_middle::mir; use rustc_target::abi::{Align, Size}; use crate::*; @@ -440,33 +440,6 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { - /// Atomic variant of read_scalar_at_offset. - fn read_scalar_at_offset_atomic( - &self, - op: &OpTy<'tcx, Provenance>, - offset: u64, - layout: TyAndLayout<'tcx>, - atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_ref(); - let value_place = this.deref_operand_and_offset(op, offset, layout)?; - this.read_scalar_atomic(&value_place, atomic) - } - - /// Atomic variant of write_scalar_at_offset. - fn write_scalar_at_offset_atomic( - &mut self, - op: &OpTy<'tcx, Provenance>, - offset: u64, - value: impl Into>, - layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let value_place = this.deref_operand_and_offset(op, offset, layout)?; - this.write_scalar_atomic(value.into(), &value_place, atomic) - } - /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, @@ -713,7 +686,10 @@ impl VClockAlloc { let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, + MiriMemoryKind::Rust + | MiriMemoryKind::Miri + | MiriMemoryKind::C + | MiriMemoryKind::WinHeap, ) | MemoryKind::Stack => { let (alloc_index, clocks) = global.current_thread_state(thread_mgr); diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index ba5ae852c5a96..dc4b435b7101c 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -193,8 +193,9 @@ impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'m pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Lazily initialize the ID of this Miri sync structure. + /// ('0' indicates uninit.) #[inline] - // Miri sync structures contain zero-initialized ids stored at some offset behind a pointer fn get_or_create_id( &mut self, next_id: Id, @@ -205,6 +206,7 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>: let value_place = this.deref_operand_and_offset(lock_op, offset, this.machine.layouts.u32)?; + // Since we are lazy, this update has to be atomic. let (old, success) = this .atomic_compare_exchange_scalar( &value_place, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index f98727186c48d..fb4d91a26d3ff 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -667,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; + let op_place = this.deref_operand(op)?; // FIXME: we still deref with the original type! let offset = Size::from_bytes(offset); // Ensure that the access is within bounds. @@ -687,17 +687,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.read_scalar(&value_place.into()) } - fn write_immediate_at_offset( - &mut self, - op: &OpTy<'tcx, Provenance>, - offset: u64, - value: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ()> { - let this = self.eval_context_mut(); - let value_place = this.deref_operand_and_offset(op, offset, value.layout)?; - this.write_immediate(**value, &value_place.into()) - } - fn write_scalar_at_offset( &mut self, op: &OpTy<'tcx, Provenance>, @@ -705,7 +694,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { value: impl Into>, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { - self.write_immediate_at_offset(op, offset, &ImmTy::from_scalar(value.into(), layout)) + let this = self.eval_context_mut(); + let value_place = this.deref_operand_and_offset(op, offset, layout)?; + this.write_scalar(value, &value_place.into()) } /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 231a99c1d034e..9a822bb0849a0 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -77,6 +77,8 @@ impl VisitTags for FrameData<'_> { pub enum MiriMemoryKind { /// `__rust_alloc` memory. Rust, + /// `miri_alloc` memory. + Miri, /// `malloc` memory. C, /// Windows `HeapAlloc` memory. @@ -110,7 +112,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap | Runtime => false, + Rust | Miri | C | WinHeap | Runtime => false, Machine | Global | ExternStatic | Tls => true, } } @@ -121,6 +123,7 @@ impl fmt::Display for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust => write!(f, "Rust heap"), + Miri => write!(f, "Miri bare-metal heap"), C => write!(f, "C heap"), WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 1b3205aabc99d..058f730833bb4 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -513,22 +513,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // Rust allocation - "__rust_alloc" => { + "__rust_alloc" | "miri_alloc" => { let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| { + let default = |this: &mut MiriInterpCx<'mir, 'tcx>| { Self::check_alloc_request(size, align)?; + let memory_kind = match link_name.as_str() { + "__rust_alloc" => MiriMemoryKind::Rust, + "miri_alloc" => MiriMemoryKind::Miri, + _ => unreachable!(), + }; + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into(), + memory_kind.into(), )?; this.write_pointer(ptr, dest) - }); + }; + + match link_name.as_str() { + "__rust_alloc" => return this.emulate_allocator(Symbol::intern("__rg_alloc"), default), + "miri_alloc" => { + default(this)?; + return Ok(EmulateByNameResult::NeedsJumping); + }, + _ => unreachable!(), + } } "__rust_alloc_zeroed" => { let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -549,20 +564,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_pointer(ptr, dest) }); } - "__rust_dealloc" => { + "__rust_dealloc" | "miri_dealloc" => { let [ptr, old_size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| { + let default = |this: &mut MiriInterpCx<'mir, 'tcx>| { + let memory_kind = match link_name.as_str() { + "__rust_dealloc" => MiriMemoryKind::Rust, + "miri_dealloc" => MiriMemoryKind::Miri, + _ => unreachable!(), + }; + // No need to check old_size/align; we anyway check that they match the allocation. this.deallocate_ptr( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), - MiriMemoryKind::Rust.into(), + memory_kind.into(), ) - }); + }; + + match link_name.as_str() { + "__rust_dealloc" => return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default), + "miri_dealloc" => { + default(this)?; + return Ok(EmulateByNameResult::NeedsJumping); + } + _ => unreachable!(), + } } "__rust_realloc" => { let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index a7275646847e2..e0afb500cb18a 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -1,8 +1,5 @@ use std::time::SystemTime; -use rustc_hir::LangItem; -use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, Ty}; - use crate::concurrency::sync::CondvarLock; use crate::concurrency::thread::{MachineCallback, Time}; use crate::*; @@ -20,39 +17,34 @@ use crate::*; /// in `pthread_mutexattr_settype` function. const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; -const MUTEX_ID_OFFSET: u64 = 4; -const RWLOCK_ID_OFFSET: u64 = 4; -const CONDVAR_ID_OFFSET: u64 = 4; - fn is_mutex_kind_default<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, - kind: Scalar, + kind: i32, ) -> InterpResult<'tcx, bool> { - Ok(kind == ecx.eval_libc("PTHREAD_MUTEX_DEFAULT")?) + Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?) } fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, - kind: Scalar, + kind: i32, ) -> InterpResult<'tcx, bool> { - let kind = kind.to_i32()?; - let mutex_normal_kind = ecx.eval_libc("PTHREAD_MUTEX_NORMAL")?.to_i32()?; + let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")?; Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) } fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriInterpCx<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) +) -> InterpResult<'tcx, i32> { + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32)?.to_i32() } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, - kind: impl Into>, + kind: i32, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) + ecx.write_scalar_at_offset(attr_op, 0, Scalar::from_i32(kind), ecx.machine.layouts.i32) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -64,53 +56,35 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &MiriInterpCx<'mir, 'tcx>, +fn mutex_get_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriInterpCx<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.read_scalar_at_offset_atomic( - mutex_op, - offset, - ecx.machine.layouts.i32, - AtomicReadOrd::Relaxed, - ) +) -> InterpResult<'tcx, MutexId> { + ecx.mutex_get_or_create_id(mutex_op, 4) } -fn mutex_set_kind<'mir, 'tcx: 'mir>( +fn mutex_reset_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, - kind: impl Into>, ) -> InterpResult<'tcx, ()> { - let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.write_scalar_at_offset_atomic( - mutex_op, - offset, - kind, - layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), - AtomicWriteOrd::Relaxed, - ) + ecx.write_scalar_at_offset(mutex_op, 4, Scalar::from_i32(0), ecx.machine.layouts.u32) } -fn mutex_get_id<'mir, 'tcx: 'mir>( +fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriInterpCx<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) +) -> InterpResult<'tcx, i32> { + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + ecx.read_scalar_at_offset(mutex_op, offset, ecx.machine.layouts.i32)?.to_i32() } -fn mutex_set_id<'mir, 'tcx: 'mir>( +fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, - id: impl Into>, + kind: i32, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_atomic( - mutex_op, - 4, - id, - layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOrd::Relaxed, - ) + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + ecx.write_scalar_at_offset(mutex_op, offset, Scalar::from_i32(kind), ecx.machine.layouts.i32) } // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. @@ -121,10 +95,10 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( // bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. fn rwlock_get_id<'mir, 'tcx: 'mir>( - ecx: &MiriInterpCx<'mir, 'tcx>, + ecx: &mut MiriInterpCx<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) +) -> InterpResult<'tcx, RwLockId> { + ecx.rwlock_get_or_create_id(rwlock_op, 4) } // pthread_condattr_t @@ -136,21 +110,16 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriInterpCx<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) +) -> InterpResult<'tcx, i32> { + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32)?.to_i32() } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, - clock_id: impl Into>, + clock_id: i32, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset( - attr_op, - 0, - clock_id, - layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty), - ) + ecx.write_scalar_at_offset(attr_op, 0, Scalar::from_i32(clock_id), ecx.machine.layouts.i32) } // pthread_cond_t @@ -163,44 +132,32 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // bytes 8-11: the clock id constant as i32 fn cond_get_id<'mir, 'tcx: 'mir>( - ecx: &MiriInterpCx<'mir, 'tcx>, + ecx: &mut MiriInterpCx<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) +) -> InterpResult<'tcx, CondvarId> { + ecx.condvar_get_or_create_id(cond_op, 4) } -fn cond_set_id<'mir, 'tcx: 'mir>( +fn cond_reset_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, - id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_atomic( - cond_op, - 4, - id, - layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOrd::Relaxed, - ) + ecx.write_scalar_at_offset(cond_op, 4, Scalar::from_i32(0), ecx.machine.layouts.u32) } fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriInterpCx<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { - ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) +) -> InterpResult<'tcx, i32> { + ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32)?.to_i32() } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, - clock_id: impl Into>, + clock_id: i32, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset( - cond_op, - 8, - clock_id, - layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), - ) + ecx.write_scalar_at_offset(cond_op, 8, Scalar::from_i32(clock_id), ecx.machine.layouts.i32) } /// Try to reacquire the mutex associated with the condition variable after we @@ -260,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; + let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?; mutexattr_set_kind(this, attr_op, default_kind)?; Ok(0) @@ -273,8 +230,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = this.read_scalar(kind_op)?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + let kind = this.read_scalar(kind_op)?.to_i32()?; + if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. // However, a mutex created by explicitly passing @@ -287,16 +244,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // use the same trick as glibc: for the case when // `pthread_mutexattr_settype` is caled explicitly, we set the // `PTHREAD_MUTEX_NORMAL_FLAG` flag. - let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG; + let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG; // Check that after setting the flag, the kind is distinguishable // from all other kinds. - assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_DEFAULT")?.to_i32()?); - assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?.to_i32()?); - assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_RECURSIVE")?.to_i32()?); - mutexattr_set_kind(this, attr_op, Scalar::from_i32(normal_kind))?; - } else if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? - || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? - || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?); + assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")?); + assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")?); + mutexattr_set_kind(this, attr_op, normal_kind)?; + } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")? + || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? { mutexattr_set_kind(this, attr_op, kind)?; } else { @@ -342,13 +299,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let attr = this.read_pointer(attr_op)?; let kind = if this.ptr_is_null(attr)? { - this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")? } else { mutexattr_get_kind(this, attr_op)? }; // Write 0 to use the same code path as the static initializers. - mutex_set_id(this, mutex_op, Scalar::from_i32(0))?; + mutex_reset_id(this, mutex_op)?; mutex_set_kind(this, mutex_op, kind)?; @@ -359,7 +316,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; - let id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = mutex_get_id(this, mutex_op)?; let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { @@ -374,9 +331,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_ub_format!("trying to acquire already locked default mutex"); } else if is_mutex_kind_normal(this, kind)? { throw_machine_stop!(TerminationInfo::Deadlock); - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EDEADLK") - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? { this.mutex_lock(id, active_thread); Ok(0) } else { @@ -399,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; - let id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = mutex_get_id(this, mutex_op)?; let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { @@ -409,10 +366,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } else { if is_mutex_kind_default(this, kind)? || is_mutex_kind_normal(this, kind)? - || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EBUSY") - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? { this.mutex_lock(id, active_thread); Ok(0) } else { @@ -435,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; - let id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = mutex_get_id(this, mutex_op)?; let active_thread = this.get_active_thread(); if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread) { @@ -453,8 +410,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_ub_format!( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ); - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? - || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? { this.eval_libc_i32("EPERM") } else { @@ -469,7 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = mutex_get_id(this, mutex_op)?; if this.mutex_is_locked(id) { throw_ub_format!("destroyed a locked mutex"); @@ -492,7 +449,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { @@ -510,7 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { @@ -527,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { @@ -557,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { @@ -574,7 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); #[allow(clippy::if_same_then_else)] @@ -593,7 +550,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.rwlock_get_or_create_id(rwlock_op, RWLOCK_ID_OFFSET)?; + let id = rwlock_get_id(this, rwlock_op)?; if this.rwlock_is_locked(id) { throw_ub_format!("destroyed a locked rwlock"); @@ -618,7 +575,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The default value of the clock attribute shall refer to the system // clock. // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setclock.html - let default_clock_id = this.eval_libc("CLOCK_REALTIME")?; + let default_clock_id = this.eval_libc_i32("CLOCK_REALTIME")?; condattr_set_clock_id(this, attr_op, default_clock_id)?; Ok(0) @@ -631,9 +588,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let clock_id = this.read_scalar(clock_id_op)?; - if clock_id == this.eval_libc("CLOCK_REALTIME")? - || clock_id == this.eval_libc("CLOCK_MONOTONIC")? + let clock_id = this.read_scalar(clock_id_op)?.to_i32()?; + if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? + || clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { condattr_set_clock_id(this, attr_op, clock_id)?; } else { @@ -652,7 +609,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; - this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?; + this.write_scalar(Scalar::from_i32(clock_id), &this.deref_operand(clk_id_op)?.into())?; Ok(Scalar::from_i32(0)) } @@ -681,13 +638,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let attr = this.read_pointer(attr_op)?; let clock_id = if this.ptr_is_null(attr)? { - this.eval_libc("CLOCK_REALTIME")? + this.eval_libc_i32("CLOCK_REALTIME")? } else { condattr_get_clock_id(this, attr_op)? }; // Write 0 to use the same code path as the static initializers. - cond_set_id(this, cond_op, Scalar::from_i32(0))?; + cond_reset_id(this, cond_op)?; cond_set_clock_id(this, cond_op, clock_id)?; @@ -696,7 +653,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?; + let id = cond_get_id(this, cond_op)?; if let Some((thread, lock)) = this.condvar_signal(id) { if let CondvarLock::Mutex(mutex) = lock { post_cond_signal(this, thread, mutex)?; @@ -713,7 +670,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { cond_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?; + let id = cond_get_id(this, cond_op)?; while let Some((thread, lock)) = this.condvar_signal(id) { if let CondvarLock::Mutex(mutex) = lock { @@ -733,8 +690,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?; - let mutex_id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = cond_get_id(this, cond_op)?; + let mutex_id = mutex_get_id(this, mutex_op)?; let active_thread = this.get_active_thread(); release_cond_mutex_and_block(this, active_thread, mutex_id)?; @@ -752,12 +709,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?; - let mutex_id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?; + let id = cond_get_id(this, cond_op)?; + let mutex_id = mutex_get_id(this, mutex_op)?; let active_thread = this.get_active_thread(); // Extract the timeout. - let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; + let clock_id = cond_get_clock_id(this, cond_op)?; let duration = match this.read_timespec(&this.deref_operand(abstime_op)?)? { Some(duration) => duration, None => { @@ -830,7 +787,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?; + let id = cond_get_id(this, cond_op)?; if this.condvar_is_awaited(id) { throw_ub_format!("destroying an awaited conditional variable"); } @@ -846,11 +803,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(0) } } - -fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { - let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); - let ty = tcx.bound_type_of(def_id).subst(*tcx, &[param.into()]); - - let param_env = tcx.param_env(def_id); - tcx.layout_of(param_env.and(ty)).unwrap() -} diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 65fd7c2eccb53..1d7ed34c59abe 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -1,5 +1,5 @@ use colored::*; -use regex::Regex; +use regex::bytes::Regex; use std::path::{Path, PathBuf}; use std::{env, process::Command}; use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; @@ -129,8 +129,8 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R macro_rules! regexes { ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! { - static ref $name: Vec<(Regex, &'static str)> = vec![ - $((Regex::new($regex).unwrap(), $replacement),)* + static ref $name: Vec<(Regex, &'static [u8])> = vec![ + $((Regex::new($regex).unwrap(), $replacement.as_bytes()),)* ]; }}; } diff --git a/src/tools/miri/tests/fail/memleak_rc.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr deleted file mode 100644 index 290de49c82c0b..0000000000000 --- a/src/tools/miri/tests/fail/memleak_rc.stderr +++ /dev/null @@ -1,11 +0,0 @@ -The following memory was leaked: ALLOC (Rust heap, size: 32, align: 8) { - 0x00 │ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ - 0x10 │ 00 00 00 00 00 00 00 00 ╾$HEX[a1765]─╼ │ ........╾──────╼ -} - -error: the evaluated program leaked memory - -note: pass `-Zmiri-ignore-leaks` to disable this check - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs new file mode 100644 index 0000000000000..f6464b5bd0181 --- /dev/null +++ b/src/tools/miri/tests/pass/miri-alloc.rs @@ -0,0 +1,29 @@ +#![feature(lang_items, start)] +#![no_std] +// windows tls dtors go through libstd right now, thus this test +// cannot pass. When windows tls dtors go through the special magic +// windows linker section, we can run this test on windows again. +//@ignore-target-windows: no-std not supported on Windows + +extern "Rust" { + fn miri_alloc(size: usize, align: usize) -> *mut u8; + fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + unsafe { + let ptr = miri_alloc(123, 1); + core::ptr::write_bytes(ptr, 0u8, 123); + miri_dealloc(ptr, 123, 1); + } + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() {} diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 80bb3b5d6a8d4..07cf89f7d338d 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -82,6 +82,8 @@ regex = { version = "1.5.6" } serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] } syn = { version = "1", features = ['full', 'visit'] } url = { version = "2.0", features = ['serde'] } +# Ensure default features of rand, which are disabled in some scenarios. +rand = { version = "0.8.5" } [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10.35", optional = true } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 35fa968f977ab..f1f5a1941579b 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -117,6 +117,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "env_logger", "expect-test", "fallible-iterator", // dependency of `thorin` + "fastrand", "filetime", "fixedbitset", "flate2",