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

Miri subtree update

r? `@ghost`
This commit is contained in:
bors 2023-10-07 07:10:56 +00:00
commit 0f3d72aa7a
90 changed files with 2403 additions and 1832 deletions

View File

@ -391,7 +391,7 @@ dependencies = [
name = "cargo-miri"
version = "0.1.0"
dependencies = [
"cargo_metadata",
"cargo_metadata 0.18.0",
"directories",
"rustc-build-sysroot",
"rustc_tools_util",
@ -423,6 +423,20 @@ dependencies = [
"thiserror",
]
[[package]]
name = "cargo_metadata"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "cargotest2"
version = "0.1.0"
@ -551,7 +565,7 @@ name = "clippy_lints"
version = "0.1.75"
dependencies = [
"arrayvec",
"cargo_metadata",
"cargo_metadata 0.15.4",
"clippy_utils",
"declare_clippy_lint",
"if_chain",
@ -1038,11 +1052,11 @@ dependencies = [
[[package]]
name = "directories"
version = "4.0.1"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
"dirs-sys 0.4.1",
]
[[package]]
@ -1051,7 +1065,7 @@ version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
"dirs-sys 0.3.7",
]
[[package]]
@ -1075,6 +1089,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
@ -2664,6 +2690,12 @@ dependencies = [
"zip",
]
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "overload"
version = "0.1.1"
@ -4686,7 +4718,7 @@ dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata",
"cargo_metadata 0.15.4",
"clap",
"diff",
"dirs",
@ -5358,7 +5390,7 @@ name = "tidy"
version = "0.1.0"
dependencies = [
"cargo-platform",
"cargo_metadata",
"cargo_metadata 0.15.4",
"ignore",
"lazy_static",
"miropt-test-tools",
@ -5663,7 +5695,7 @@ dependencies = [
"anyhow",
"bstr",
"cargo-platform",
"cargo_metadata",
"cargo_metadata 0.15.4",
"color-eyre",
"colored",
"comma",
@ -5690,7 +5722,7 @@ dependencies = [
"anyhow",
"bstr",
"cargo-platform",
"cargo_metadata",
"cargo_metadata 0.15.4",
"color-eyre",
"colored",
"comma",

View File

@ -71,19 +71,12 @@ and you can (cross-)run the entire test suite using:
MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test
```
If your target doesn't support libstd, you can run miri with
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_NO_STD=1 MIRI_TEST_TARGET=thumbv7em-none-eabihf ./miri test tests/fail/alloc/no_global_allocator.rs
MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf
```
to avoid attempting (and failing) to build libstd. Note that almost no tests will pass
this way, but you can run individual tests.
`./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).
`./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
to `cargo test`, so for multiple filers you need to use `./miri test -- FILTER1 FILTER2`.
You can get a trace of which MIR statements are being executed by setting the
`MIRI_LOG` environment variable. For example:

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.0.1"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
@ -47,9 +47,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.71"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "autocfg"
@ -59,9 +59,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.67"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
@ -86,30 +86,29 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "bstr"
version = "1.4.0"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09"
checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
dependencies = [
"memchr",
"once_cell",
"regex-automata",
"serde",
]
[[package]]
name = "camino"
version = "1.1.4"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2"
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479"
dependencies = [
"serde",
]
@ -130,9 +129,12 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.79"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
@ -209,21 +211,21 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "ctrlc"
version = "3.2.5"
version = "3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639"
checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
dependencies = [
"nix",
"windows-sys 0.45.0",
"windows-sys 0.48.0",
]
[[package]]
@ -247,9 +249,9 @@ dependencies = [
[[package]]
name = "errno"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
dependencies = [
"errno-dragonfly",
"libc",
@ -278,18 +280,15 @@ dependencies = [
[[package]]
name = "fastrand"
version = "1.9.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "getrandom"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
@ -298,15 +297,15 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.27.2"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "hermit-abi"
version = "0.3.1"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "humantime"
@ -342,17 +341,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "io-lifetimes"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "is-terminal"
version = "0.4.9"
@ -360,15 +348,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix 0.38.14",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "lazy_static"
@ -409,9 +397,9 @@ dependencies = [
[[package]]
name = "libloading"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb"
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
@ -419,21 +407,15 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.3.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
[[package]]
name = "linux-raw-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
[[package]]
name = "lock_api"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
@ -441,12 +423,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "measureme"
@ -464,9 +443,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memmap2"
@ -479,9 +458,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.6.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
@ -510,14 +489,13 @@ dependencies = [
[[package]]
name = "nix"
version = "0.26.2"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.4.0",
"cfg-if",
"libc",
"static_assertions",
]
[[package]]
@ -528,18 +506,18 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "object"
version = "0.30.3"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.17.1"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "owo-colors"
@ -592,9 +570,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.9"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "portable-atomic"
@ -620,9 +598,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@ -686,26 +664,32 @@ dependencies = [
[[package]]
name = "regex"
version = "1.8.1"
version = "1.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
dependencies = [
"aho-corasick",
"memchr",
"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.7.1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "rustc-demangle"
@ -742,66 +726,52 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.19"
version = "0.38.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.3.7",
"windows-sys 0.48.0",
]
[[package]]
name = "rustix"
version = "0.38.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.7",
"linux-raw-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "scopeguard"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.17"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.185"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.185"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
@ -810,9 +780,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.96"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
@ -821,30 +791,24 @@ dependencies = [
[[package]]
name = "sharded-slab"
version = "0.1.4"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "smallvec"
version = "1.10.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "syn"
version = "2.0.29"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -853,40 +817,40 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.5.0"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
"rustix 0.37.19",
"windows-sys 0.45.0",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "termcolor"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.40"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [
"proc-macro2",
"quote",
@ -916,9 +880,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.30"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
dependencies = [
"once_cell",
"valuable",
@ -974,9 +938,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
@ -1014,9 +978,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
@ -1042,7 +1006,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
"windows-targets 0.48.5",
]
[[package]]
@ -1062,17 +1026,17 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@ -1083,9 +1047,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
@ -1095,9 +1059,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
@ -1107,9 +1071,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
@ -1119,9 +1083,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
@ -1131,9 +1095,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
@ -1143,9 +1107,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
@ -1155,9 +1119,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "yansi-term"

View File

@ -480,8 +480,10 @@ Moreover, Miri recognizes some environment variables:
purpose.
* `MIRI_TEST_THREADS` (recognized by the test suite): set the number of threads to use for running tests.
By default the number of cores is used.
* `MIRI_NO_STD` (recognized by `cargo miri` and the test suite) makes sure that the target's
sysroot is built without libstd. This allows testing and running no_std programs.
* `MIRI_NO_STD` (recognized by `cargo miri`) makes sure that the target's sysroot is built without
libstd. This allows testing and running no_std programs.
(Miri has a heuristic to detect no-std targets based on the target name; this environment variable
is only needed when that heuristic fails.)
* `RUSTC_BLESS` (recognized by the test suite and `cargo-miri-test/run-test.py`): overwrite all
`stderr` and `stdout` files instead of checking whether the output matches.
* `MIRI_SKIP_UI_CHECKS` (recognized by the test suite): don't check whether the

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "anyhow"
version = "1.0.71"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "bitflags"
@ -15,10 +15,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "camino"
version = "1.1.4"
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "camino"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
dependencies = [
"serde",
]
@ -38,18 +44,18 @@ dependencies = [
[[package]]
name = "cargo-platform"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.15.4"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8"
dependencies = [
"camino",
"cargo-platform",
@ -61,9 +67,12 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.79"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
@ -73,33 +82,34 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "directories"
version = "4.0.1"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"winapi",
"windows-sys",
]
[[package]]
name = "errno"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys 0.48.0",
"windows-sys",
]
[[package]]
@ -114,73 +124,50 @@ dependencies = [
[[package]]
name = "fastrand"
version = "1.9.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "getrandom"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "io-lifetimes"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "libc"
version = "0.2.142"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "linux-raw-sys"
version = "0.3.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@ -200,7 +187,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -209,7 +196,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -251,47 +238,46 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.19"
version = "0.38.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
dependencies = [
"bitflags",
"bitflags 2.4.0",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "semver"
version = "1.0.17"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.185"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.185"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
@ -300,9 +286,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.96"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
@ -311,9 +297,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.29"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -322,31 +308,31 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.5.0"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
"rustix",
"windows-sys 0.45.0",
"windows-sys",
]
[[package]]
name = "thiserror"
version = "1.0.40"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [
"proc-macro2",
"quote",
@ -355,9 +341,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
@ -365,156 +351,68 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View File

@ -14,10 +14,10 @@ test = false # we have no unit tests
doctest = false # and no doc tests
[dependencies]
directories = "4"
directories = "5"
rustc_version = "0.4"
serde_json = "1.0.40"
cargo_metadata = "0.15.0"
cargo_metadata = "0.18.0"
rustc-build-sysroot = "0.4.1"
# Enable some feature flags that dev-dependencies need but dependencies

View File

@ -74,7 +74,17 @@ pub fn setup(
}
};
// Sysroot configuration and build details.
let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() {
let no_std = match std::env::var_os("MIRI_NO_STD") {
None =>
// No-std heuristic taken from rust/src/bootstrap/config.rs
// (https://github.com/rust-lang/rust/blob/25b5af1b3a0b9e2c0c57b223b2d0e3e203869b2c/src/bootstrap/config.rs#L549-L555).
target.contains("-none")
|| target.contains("nvptx")
|| target.contains("switch")
|| target.contains("-uefi"),
Some(val) => val != "0",
};
let sysroot_config = if no_std {
SysrootConfig::NoStd
} else {
SysrootConfig::WithStd {

View File

@ -112,7 +112,7 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # no_std embedded architecture
MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
;;
x86_64-apple-darwin)

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "anyhow"
version = "1.0.71"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "bitflags"
@ -14,6 +14,21 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -22,22 +37,23 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "directories"
version = "4.0.1"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"winapi",
"windows-sys",
]
[[package]]
@ -48,9 +64,30 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "either"
version = "1.8.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "errno"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "getrandom"
@ -64,19 +101,34 @@ dependencies = [
]
[[package]]
name = "itertools"
version = "0.10.5"
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "linux-raw-sys"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
[[package]]
name = "miri-script"
@ -96,9 +148,15 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.17.1"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "path_macro"
@ -108,9 +166,9 @@ checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15"
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@ -130,7 +188,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -153,6 +211,19 @@ dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "same-file"
version = "1.0.6"
@ -164,9 +235,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.17"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
[[package]]
name = "shell-words"
@ -176,9 +247,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "syn"
version = "2.0.29"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -187,18 +258,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.47"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.47"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [
"proc-macro2",
"quote",
@ -207,15 +278,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "walkdir"
version = "2.3.3"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
@ -229,13 +300,14 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.4.0"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"libc",
"home",
"once_cell",
"rustix",
]
[[package]]
@ -256,9 +328,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
@ -270,16 +342,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xshell"
version = "0.2.3"
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "962c039b3a7b16cf4e9a4248397c6585c07547412e7d6a6e035389a802dcfe90"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "xshell"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
dependencies = [
"xshell-macros",
]
[[package]]
name = "xshell-macros"
version = "0.2.3"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbabb1cbd15a1d6d12d9ed6b35cc6777d4af87ab3ba155ea37215f20beab80c"
checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"

View File

@ -13,11 +13,11 @@ edition = "2021"
[dependencies]
which = "4.4"
walkdir = "2.3"
itertools = "0.10"
itertools = "0.11"
path_macro = "1.0"
shell-words = "1.1"
anyhow = "1.0"
xshell = "0.2"
rustc_version = "0.4"
dunce = "1.0.4"
directories = "4"
directories = "5"

View File

@ -37,7 +37,10 @@ impl MiriEnv {
Err(_) => vec![],
};
if !quiet {
eprintln!("$ (building Miri sysroot)");
match self.sh.var("MIRI_TEST_TARGET") {
Ok(target) => eprintln!("$ (building Miri sysroot for {target})"),
Err(_) => eprintln!("$ (building Miri sysroot)"),
}
}
let output = cmd!(self.sh,
"cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} --

View File

@ -1 +1 @@
bb6c66be3793ac5c738eeac91ecdc4b99388d0b4
4ea5190026dbc1302b644d938e68bc6843cb8b24

View File

@ -66,10 +66,13 @@ pub struct FrameState {
/// `stacked_borrows::GlobalState` upon function return, and if we attempt to pop a protected
/// tag, to identify which call is responsible for protecting the tag.
/// See `Stack::item_popped` for more explanation.
/// Tree Borrows also needs to know which allocation these tags
/// belong to so that it can perform a read through them immediately before
/// the frame gets popped.
///
/// This will contain one tag per reference passed to the function, so
/// a size of 2 is enough for the vast majority of functions.
pub protected_tags: SmallVec<[BorTag; 2]>,
pub protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
}
impl VisitTags for FrameState {
@ -208,7 +211,7 @@ impl GlobalStateInner {
}
pub fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
for tag in &frame
for (_, tag) in &frame
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
@ -305,7 +308,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
fn protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
fn protect_place(
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
match method {
@ -450,6 +456,19 @@ impl AllocState {
AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags),
}
}
/// Tree Borrows needs to be told when a tag stops being protected.
pub fn release_protector<'tcx>(
&self,
machine: &MiriMachine<'_, 'tcx>,
global: &GlobalState,
tag: BorTag,
) -> InterpResult<'tcx> {
match self {
AllocState::StackedBorrows(_sb) => Ok(()),
AllocState::TreeBorrows(tb) => tb.borrow_mut().release_protector(machine, global, tag),
}
}
}
impl VisitTags for AllocState {

View File

@ -436,6 +436,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
ProtectorKind::WeakProtector => "weakly protected",
ProtectorKind::StrongProtector => "strongly protected",
};
let item_tag = item.tag();
let call_id = self
.machine
.threads
@ -444,7 +445,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
.map(|frame| {
frame.extra.borrow_tracker.as_ref().expect("we should have borrow tracking data")
})
.find(|frame| frame.protected_tags.contains(&item.tag()))
.find(|frame| frame.protected_tags.iter().any(|(_, tag)| tag == &item_tag))
.map(|frame| frame.call_id)
.unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here?
match self.operation {

View File

@ -719,7 +719,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
if let Some(protect) = new_perm.protector() {
// See comment in `Stack::item_invalidated` for why we store the tag twice.
this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag);
this.frame_mut()
.extra
.borrow_tracker
.as_mut()
.unwrap()
.protected_tags
.push((alloc_id, new_tag));
this.machine
.borrow_tracker
.as_mut()
@ -810,6 +816,32 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
}
fn sb_retag_place(
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
new_perm: NewPermission,
info: RetagInfo, // diagnostics info about this retag
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
let size = this.size_and_align_of_mplace(place)?.map(|(size, _)| size);
// FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
// bail out -- we cannot reasonably figure out which memory range to reborrow.
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
let size = match size {
Some(size) => size,
None => return Ok(place.clone()),
};
// Compute new borrow.
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
// Reborrow.
let new_prov = this.sb_reborrow(place, size, new_perm, new_tag, info)?;
// Adjust place.
Ok(place.clone().map_provenance(|_| new_prov))
}
/// Retags an individual pointer, returning the retagged version.
/// `kind` indicates what kind of reference is being created.
fn sb_retag_reference(
@ -819,27 +851,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
info: RetagInfo, // diagnostics info about this retag
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
// We want a place for where the ptr *points to*, so we get one.
let place = this.ref_to_mplace(val)?;
let size = this.size_and_align_of_mplace(&place)?.map(|(size, _)| size);
// FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
// bail out -- we cannot reasonably figure out which memory range to reborrow.
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
let size = match size {
Some(size) => size,
None => return Ok(val.clone()),
};
// Compute new borrow.
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
// Reborrow.
let new_prov = this.sb_reborrow(&place, size, new_perm, new_tag, info)?;
// Adjust pointer.
let new_place = place.map_provenance(|_| new_prov);
// Return new pointer.
let new_place = this.sb_retag_place(&place, new_perm, info)?;
Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
}
}
@ -972,26 +985,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// call.
///
/// This is used to ensure soundness of in-place function argument/return passing.
fn sb_protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
fn sb_protect_place(
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
// We have to turn the place into a pointer to use the usual retagging logic.
// (The pointer type does not matter, so we use a raw pointer.)
let ptr = this.mplace_to_ref(place)?;
// Reborrow it. With protection! That is the entire point.
// Retag it. With protection! That is the entire point.
let new_perm = NewPermission::Uniform {
perm: Permission::Unique,
access: Some(AccessKind::Write),
protector: Some(ProtectorKind::StrongProtector),
};
let _new_ptr = this.sb_retag_reference(
&ptr,
this.sb_retag_place(
place,
new_perm,
RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false },
)?;
// We just throw away `new_ptr`, so nobody can access this memory while it is protected.
Ok(())
)
}
/// Mark the given tag as exposed. It was found on a pointer with the given AllocId.

View File

@ -19,6 +19,7 @@ pub enum AccessCause {
Explicit(AccessKind),
Reborrow,
Dealloc,
FnExit,
}
impl fmt::Display for AccessCause {
@ -27,6 +28,7 @@ impl fmt::Display for AccessCause {
Self::Explicit(kind) => write!(f, "{kind}"),
Self::Reborrow => write!(f, "reborrow"),
Self::Dealloc => write!(f, "deallocation"),
Self::FnExit => write!(f, "protector release"),
}
}
}
@ -38,6 +40,7 @@ impl AccessCause {
Self::Explicit(kind) => format!("{rel} {kind}"),
Self::Reborrow => format!("reborrow (acting as a {rel} read access)"),
Self::Dealloc => format!("deallocation (acting as a {rel} write access)"),
Self::FnExit => format!("protector release (acting as a {rel} read access)"),
}
}
}
@ -52,7 +55,9 @@ pub struct Event {
/// Relative position of the tag to the one used for the access.
pub is_foreign: bool,
/// User-visible range of the access.
pub access_range: AllocRange,
/// `None` means that this is an implicit access to the entire allocation
/// (used for the implicit read on protector release).
pub access_range: Option<AllocRange>,
/// The transition recorded by this event only occured on a subrange of
/// `access_range`: a single access on `access_range` triggers several events,
/// each with their own mutually disjoint `transition_range`. No-op transitions
@ -123,7 +128,17 @@ impl HistoryData {
// NOTE: `transition_range` is explicitly absent from the error message, it has no significance
// to the user. The meaningful one is `access_range`.
let access = access_cause.print_as_access(is_foreign);
self.events.push((Some(span.data()), format!("{this} later transitioned to {endpoint} due to a {access} at offsets {access_range:?}", endpoint = transition.endpoint())));
let access_range_text = match access_range {
Some(r) => format!("at offsets {r:?}"),
None => format!("on every location previously accessed by this tag"),
};
self.events.push((
Some(span.data()),
format!(
"{this} later transitioned to {endpoint} due to a {access} {access_range_text}",
endpoint = transition.endpoint()
),
));
self.events
.push((None, format!("this transition corresponds to {}", transition.summary())));
}
@ -745,7 +760,7 @@ const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt {
bot: '',
warning_text: "Warning: this tree is indicative only. Some tags may have been hidden.",
},
perm: DisplayFmtPermission { open: "|", sep: "|", close: "|", uninit: "---", range_sep: ".." },
perm: DisplayFmtPermission { open: "|", sep: "|", close: "|", uninit: "----", range_sep: ".." },
padding: DisplayFmtPadding {
join_middle: "",
join_last: "",

View File

@ -2,10 +2,16 @@ use log::trace;
use rustc_target::abi::{Abi, Align, Size};
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
use crate::borrow_tracker::{
AccessKind, GlobalState, GlobalStateInner, ProtectorKind, RetagFields,
};
use rustc_middle::{
mir::{Mutability, RetagKind},
ty::{self, layout::HasParamEnv, Ty},
ty::{
self,
layout::{HasParamEnv, HasTyCtxt},
Ty,
},
};
use rustc_span::def_id::DefId;
@ -66,7 +72,7 @@ impl<'tcx> Tree {
self.perform_access(
access_kind,
tag,
range,
Some(range),
global,
span,
diagnostics::AccessCause::Explicit(access_kind),
@ -95,6 +101,29 @@ impl<'tcx> Tree {
pub fn expose_tag(&mut self, _tag: BorTag) {
// TODO
}
/// A tag just lost its protector.
///
/// This emits a special kind of access that is only applied
/// to initialized locations, as a protection against other
/// tags not having been made aware of the existence of this
/// protector.
pub fn release_protector(
&mut self,
machine: &MiriMachine<'_, 'tcx>,
global: &GlobalState,
tag: BorTag,
) -> InterpResult<'tcx> {
let span = machine.current_span();
self.perform_access(
AccessKind::Read,
tag,
None, // no specified range because it occurs on the entire allocation
global,
span,
diagnostics::AccessCause::FnExit,
)
}
}
/// Policy for a new borrow.
@ -174,6 +203,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
new_tag: BorTag,
) -> InterpResult<'tcx, Option<Provenance>> {
let this = self.eval_context_mut();
// Make sure the new permission makes sense as the initial permission of a fresh tag.
assert!(new_perm.initial_state.is_initial());
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
this.check_ptr_access_align(
place.ptr(),
@ -242,7 +273,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
// We register the protection in two different places.
// This makes creating a protector slower, but checking whether a tag
// is protected faster.
this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag);
this.frame_mut()
.extra
.borrow_tracker
.as_mut()
.unwrap()
.protected_tags
.push((alloc_id, new_tag));
this.machine
.borrow_tracker
.as_mut()
@ -269,52 +306,31 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
tree_borrows.perform_access(
AccessKind::Read,
orig_tag,
range,
Some(range),
this.machine.borrow_tracker.as_ref().unwrap(),
this.machine.current_span(),
diagnostics::AccessCause::Reborrow,
)?;
// Record the parent-child pair in the tree.
// FIXME: We should eventually ensure that the following `assert` holds, because
// some "exhaustive" tests consider only the initial configurations that satisfy it.
// The culprit is `Permission::new_active` in `tb_protect_place`.
//assert!(new_perm.initial_state.is_initial());
tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range, span)?;
drop(tree_borrows);
// Also inform the data race model (but only if any bytes are actually affected).
if range.size.bytes() > 0 {
if let Some(data_race) = alloc_extra.data_race.as_ref() {
// We sometimes need to make it a write, since not all retags commute with reads!
// FIXME: Is that truly the semantics we want? Some optimizations are likely to be
// very unhappy without this. We'd tsill ge some UB just by picking a suitable
// interleaving, but wether UB happens can depend on whether a write occurs in the
// future...
let is_write = new_perm.initial_state.is_active()
|| (new_perm.initial_state.is_reserved(None) && new_perm.protector.is_some());
if is_write {
// Need to get mutable access to alloc_extra.
// (Cannot always do this as we can do read-only reborrowing on read-only allocations.)
let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?;
alloc_extra.data_race.as_mut().unwrap().write(alloc_id, range, machine)?;
} else {
data_race.read(alloc_id, range, &this.machine)?;
}
data_race.read(alloc_id, range, &this.machine)?;
}
}
Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
}
/// Retags an individual pointer, returning the retagged version.
fn tb_retag_reference(
fn tb_retag_place(
&mut self,
val: &ImmTy<'tcx, Provenance>,
place: &MPlaceTy<'tcx, Provenance>,
new_perm: NewPermission,
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
// We want a place for where the ptr *points to*, so we get one.
let place = this.ref_to_mplace(val)?;
// Determine the size of the reborrow.
// For most types this is the entire size of the place, however
@ -323,7 +339,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
// then we override the size to do a zero-length reborrow.
let reborrow_size = match new_perm {
NewPermission { zero_size: false, .. } =>
this.size_and_align_of_mplace(&place)?
this.size_and_align_of_mplace(place)?
.map(|(size, _)| size)
.unwrap_or(place.layout.size),
_ => Size::from_bytes(0),
@ -339,12 +355,21 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
// Compute the actual reborrow.
let new_prov = this.tb_reborrow(&place, reborrow_size, new_perm, new_tag)?;
let new_prov = this.tb_reborrow(place, reborrow_size, new_perm, new_tag)?;
// Adjust pointer.
let new_place = place.map_provenance(|_| new_prov);
// Adjust place.
Ok(place.clone().map_provenance(|_| new_prov))
}
// Return new pointer.
/// Retags an individual pointer, returning the retagged version.
fn tb_retag_reference(
&mut self,
val: &ImmTy<'tcx, Provenance>,
new_perm: NewPermission,
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
let place = this.ref_to_mplace(val)?;
let new_place = this.tb_retag_place(&place, new_perm)?;
Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
}
}
@ -493,22 +518,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// call.
///
/// This is used to ensure soundness of in-place function argument/return passing.
fn tb_protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
fn tb_protect_place(
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
// We have to turn the place into a pointer to use the usual retagging logic.
// (The pointer type does not matter, so we use a raw pointer.)
let ptr = this.mplace_to_ref(place)?;
// Reborrow it. With protection! That is the entire point.
// Retag it. With protection! That is the entire point.
let new_perm = NewPermission {
initial_state: Permission::new_active(),
initial_state: Permission::new_reserved(
place.layout.ty.is_freeze(this.tcx(), this.param_env()),
),
zero_size: false,
protector: Some(ProtectorKind::StrongProtector),
};
let _new_ptr = this.tb_retag_reference(&ptr, new_perm)?;
// We just throw away `new_ptr`, so nobody can access this memory while it is protected.
Ok(())
this.tb_retag_place(place, new_perm)
}
/// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
@ -525,7 +549,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// if converting this alloc_id from a global to a local one
// uncovers a non-supported `extern static`.
let alloc_extra = this.get_alloc_extra(alloc_id)?;
trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}");
alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag);
}
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {

View File

@ -10,9 +10,18 @@ use crate::borrow_tracker::AccessKind;
enum PermissionPriv {
/// represents: a local reference that has not yet been written to;
/// allows: child reads, foreign reads, foreign writes if type is freeze;
/// rejects: child writes (Active), foreign writes (Disabled, except if type is not freeze).
/// special case: behaves differently when protected to adhere more closely to noalias
Reserved { ty_is_freeze: bool },
/// affected by: child writes (becomes Active),
/// rejects: foreign writes (Disabled, except if type is not freeze).
///
/// special case: behaves differently when protected, which is where `conflicted`
/// is relevant
/// - `conflicted` is set on foreign reads,
/// - `conflicted` must not be set on child writes (there is UB otherwise).
/// This is so that the behavior of `Reserved` adheres to the rules of `noalias`:
/// - foreign-read then child-write is UB due to `conflicted`,
/// - child-write then foreign-read is UB since child-write will activate and then
/// foreign-read disables a protected `Active`, which is UB.
Reserved { ty_is_freeze: bool, conflicted: bool },
/// represents: a unique pointer;
/// allows: child reads, child writes;
/// rejects: foreign reads (Frozen), foreign writes (Disabled).
@ -29,10 +38,11 @@ enum PermissionPriv {
use PermissionPriv::*;
impl PartialOrd for PermissionPriv {
/// PermissionPriv is ordered as follows:
/// - Reserved(_) < Active < Frozen < Disabled;
/// - different kinds of `Reserved` (with or without interior mutability)
/// are incomparable to each other.
/// PermissionPriv is ordered by the reflexive transitive closure of
/// `Reserved(conflicted=false) < Reserved(conflicted=true) < Active < Frozen < Disabled`.
/// `Reserved` that have incompatible `ty_is_freeze` are incomparable to each other.
/// This ordering matches the reachability by transitions, as asserted by the exhaustive test
/// `permissionpriv_partialord_is_reachability`.
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
use Ordering::*;
Some(match (self, other) {
@ -43,7 +53,17 @@ impl PartialOrd for PermissionPriv {
(_, Frozen) => Less,
(Active, _) => Greater,
(_, Active) => Less,
(Reserved { .. }, Reserved { .. }) => return None,
(
Reserved { ty_is_freeze: f1, conflicted: c1 },
Reserved { ty_is_freeze: f2, conflicted: c2 },
) => {
// No transition ever changes `ty_is_freeze`.
if f1 != f2 {
return None;
}
// `bool` is ordered such that `false <= true`, so this works as intended.
c1.cmp(c2)
}
})
}
}
@ -51,7 +71,7 @@ impl PartialOrd for PermissionPriv {
impl PermissionPriv {
/// Check if `self` can be the initial state of a pointer.
fn is_initial(&self) -> bool {
matches!(self, Reserved { ty_is_freeze: _ } | Frozen)
matches!(self, Reserved { conflicted: false, .. } | Frozen)
}
}
@ -66,12 +86,13 @@ mod transition {
Some(match state {
Disabled => return None,
// The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
// accesses, since the data is not being mutated. Hence the `{ .. }`
// accesses, since the data is not being mutated. Hence the `{ .. }`.
readable @ (Reserved { .. } | Active | Frozen) => readable,
})
}
/// A non-child node was read-accessed: noop on non-protected Reserved, advance to Frozen otherwise.
/// A non-child node was read-accessed: keep `Reserved` but mark it as `conflicted` if it
/// is protected; invalidate `Active`.
fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
Some(match state {
// Non-writeable states just ignore foreign reads.
@ -79,16 +100,14 @@ mod transition {
// Writeable states are more tricky, and depend on whether things are protected.
// The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
// accesses, since the data is not being mutated. Hence the `{ .. }`
res @ Reserved { .. } =>
if protected {
// Someone else read, make sure we won't write.
// We could make this `Disabled` but it doesn't look like we get anything out of that extra UB.
Frozen
} else {
// Before activation and without protectors, foreign reads are fine.
// That's the entire point of 2-phase borrows.
res
},
// Someone else read. To make sure we won't write before function exit,
// we set the "conflicted" flag, which will disallow writes while we are protected.
Reserved { ty_is_freeze, .. } if protected =>
Reserved { ty_is_freeze, conflicted: true },
// Before activation and without protectors, foreign reads are fine.
// That's the entire point of 2-phase borrows.
res @ Reserved { .. } => res,
Active =>
if protected {
// We wrote, someone else reads -- that's bad.
@ -104,8 +123,12 @@ mod transition {
/// A child node was write-accessed: `Reserved` must become `Active` to obtain
/// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
fn child_write(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> {
fn child_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
Some(match state {
// If the `conflicted` flag is set, then there was a foreign read during
// the function call that is still ongoing (still `protected`),
// this is UB (`noalias` violation).
Reserved { conflicted: true, .. } if protected => return None,
// A write always activates the 2-phase borrow, even with interior
// mutability
Reserved { .. } | Active => Active,
@ -117,7 +140,8 @@ mod transition {
/// non-protected interior mutable `Reserved` which stay the same.
fn foreign_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
Some(match state {
cell @ Reserved { ty_is_freeze: false } if !protected => cell,
Reserved { .. } if protected => Disabled,
res @ Reserved { ty_is_freeze: false, .. } => res,
_ => Disabled,
})
}
@ -159,13 +183,14 @@ impl Permission {
}
/// Default initial permission of the root of a new tree.
/// Must *only* be used for the root, this is not in general an "initial" permission!
pub fn new_active() -> Self {
Self { inner: Active }
}
/// Default initial permission of a reborrowed mutable reference.
pub fn new_reserved(ty_is_freeze: bool) -> Self {
Self { inner: Reserved { ty_is_freeze } }
Self { inner: Reserved { ty_is_freeze, conflicted: false } }
}
/// Default initial permission of a reborrowed shared reference
@ -173,28 +198,6 @@ impl Permission {
Self { inner: Frozen }
}
pub fn is_active(self) -> bool {
matches!(self.inner, Active)
}
// Leave `interior_mut` as `None` if interior mutability
// is irrelevant.
pub fn is_reserved(self, interior_mut: Option<bool>) -> bool {
match (interior_mut, self.inner) {
(None, Reserved { .. }) => true,
(Some(b1), Reserved { ty_is_freeze: b2 }) => b1 == b2,
_ => false,
}
}
pub fn is_frozen(self) -> bool {
matches!(self.inner, Frozen)
}
pub fn is_disabled(self) -> bool {
matches!(self.inner, Disabled)
}
/// Apply the transition to the inner PermissionPriv.
pub fn perform_access(
kind: AccessKind,
@ -250,8 +253,12 @@ pub mod diagnostics {
f,
"{}",
match self {
Reserved { ty_is_freeze: true } => "Reserved",
Reserved { ty_is_freeze: false } => "Reserved (interior mutable)",
Reserved { ty_is_freeze: true, conflicted: false } => "Reserved",
Reserved { ty_is_freeze: true, conflicted: true } => "Reserved (conflicted)",
Reserved { ty_is_freeze: false, conflicted: false } =>
"Reserved (interior mutable)",
Reserved { ty_is_freeze: false, conflicted: true } =>
"Reserved (interior mutable, conflicted)",
Active => "Active",
Frozen => "Frozen",
Disabled => "Disabled",
@ -279,11 +286,13 @@ pub mod diagnostics {
// and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
// alignment will be incorrect.
match self.inner {
Reserved { ty_is_freeze: true } => "Res",
Reserved { ty_is_freeze: false } => "Re*",
Active => "Act",
Frozen => "Frz",
Disabled => "Dis",
Reserved { ty_is_freeze: true, conflicted: false } => "Rs ",
Reserved { ty_is_freeze: true, conflicted: true } => "RsC ",
Reserved { ty_is_freeze: false, conflicted: false } => "RsM ",
Reserved { ty_is_freeze: false, conflicted: true } => "RsCM",
Active => "Act ",
Frozen => "Frz ",
Disabled => "Dis ",
}
}
}
@ -291,15 +300,13 @@ pub mod diagnostics {
impl PermTransition {
/// Readable explanation of the consequences of an event.
/// Fits in the sentence "This accessed caused {trans.summary()}".
///
/// Important: for the purposes of this explanation, `Reserved` is considered
/// to have write permissions, because that's what the diagnostics care about
/// (otherwise `Reserved -> Frozen` would be considered a noop).
pub fn summary(&self) -> &'static str {
assert!(self.is_possible());
match (self.from, self.to) {
(_, Active) => "the first write to a 2-phase borrowed mutable reference",
(_, Frozen) => "a loss of write permissions",
(Reserved { conflicted: false, .. }, Reserved { conflicted: true, .. }) =>
"a temporary loss of write permissions until function exit",
(Frozen, Disabled) => "a loss of read permissions",
(_, Disabled) => "a loss of read and write permissions",
(old, new) =>
@ -314,7 +321,7 @@ pub mod diagnostics {
/// Irrelevant events:
/// - modifications of write permissions when the error is related to read permissions
/// (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Active`,
/// `Reserved -> Frozen`, and `Active -> Frozen`)
/// `Reserved(conflicted=false) -> Reserved(conflicted=true)`, and `Active -> Frozen`)
/// - all transitions for attempts to deallocate strongly protected tags
///
/// # Panics
@ -325,8 +332,9 @@ pub mod diagnostics {
/// (Reserved < Active < Frozen < Disabled);
/// - between `self` and `err` the permission should also be increasing,
/// so all permissions inside `err` should be greater than `self.1`;
/// - `Active` and `Reserved` cannot cause an error due to insufficient permissions,
/// so `err` cannot be a `ChildAccessForbidden(_)` of either of them;
/// - `Active` and `Reserved(conflicted=false)` cannot cause an error
/// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)`
/// of either of them;
/// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
/// tag should not have been `Disabled` in the first place (if this occurs it means
/// we have unprotected tags that become protected)
@ -346,23 +354,28 @@ pub mod diagnostics {
(Frozen, Frozen) => true,
(Active, Frozen) => true,
(Disabled, Disabled) => true,
(Reserved { conflicted: true, .. }, Reserved { conflicted: true, .. }) =>
true,
// A pointer being `Disabled` is a strictly stronger source of
// errors than it being `Frozen`. If we try to access a `Disabled`,
// then where it became `Frozen` (or `Active`) is the least of our concerns for now.
(Active | Frozen, Disabled) => false,
// then where it became `Frozen` (or `Active` or `Reserved`) is the least
// of our concerns for now.
(Reserved { conflicted: true, .. } | Active | Frozen, Disabled) => false,
(Reserved { conflicted: true, .. }, Frozen) => false,
// `Active` and `Reserved` have all permissions, so a
// `ChildAccessForbidden(Reserved | Active)` can never exist.
(_, Active) | (_, Reserved { .. }) =>
(_, Active) | (_, Reserved { conflicted: false, .. }) =>
unreachable!("this permission cannot cause an error"),
// No transition has `Reserved` as its `.to` unless it's a noop.
(Reserved { .. }, _) => unreachable!("self is a noop transition"),
// No transition has `Reserved(conflicted=false)` as its `.to` unless it's a noop.
(Reserved { conflicted: false, .. }, _) =>
unreachable!("self is a noop transition"),
// All transitions produced in normal executions (using `apply_access`)
// change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
// We assume that the error was triggered on the same location that
// the transition `self` applies to, so permissions found must be increasing
// in the order `self.from < self.to <= insufficient.inner`
(Disabled, Frozen) =>
(Active | Frozen | Disabled, Reserved { .. }) | (Disabled, Frozen) =>
unreachable!("permissions between self and err must be increasing"),
}
}
@ -372,25 +385,34 @@ pub mod diagnostics {
// This eliminates transitions like `Reserved -> Active`
// when the error is a `Frozen -> Disabled`.
match (self.to, before_disabled.inner) {
// We absolutely want to know where it was activated.
// We absolutely want to know where it was activated/frozen/marked
// conflicted.
(Active, Active) => true,
// And knowing where it became Frozen is also important.
(Frozen, Frozen) => true,
(Reserved { conflicted: true, .. }, Reserved { conflicted: true, .. }) =>
true,
// If the error is a transition `Frozen -> Disabled`, then we don't really
// care whether before that was `Reserved -> Active -> Frozen` or
// `Reserved -> Frozen` or even `Frozen` directly.
// `Frozen` directly.
// The error will only show either
// - created as Frozen, then Frozen -> Disabled is forbidden
// - created as Reserved, later became Frozen, then Frozen -> Disabled is forbidden
// In both cases the `Reserved -> Active` part is inexistant or irrelevant.
// - created as Reserved { conflicted: false },
// then Reserved { .. } -> Disabled is forbidden
// - created as Reserved { conflicted: false },
// then Active -> Disabled is forbidden
// A potential `Reserved { conflicted: false }
// -> Reserved { conflicted: true }` is inexistant or irrelevant,
// and so is the `Reserved { conflicted: false } -> Active`
(Active, Frozen) => false,
(Reserved { conflicted: true, .. }, _) => false,
(_, Disabled) =>
unreachable!(
"permission that results in Disabled should not itself be Disabled in the first place"
),
// No transition has `Reserved` as its `.to` unless it's a noop.
(Reserved { .. }, _) => unreachable!("self is a noop transition"),
// No transition has `Reserved { conflicted: false }` as its `.to`
// unless it's a noop.
(Reserved { conflicted: false, .. }, _) =>
unreachable!("self is a noop transition"),
// Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
// so permissions found must be increasing in the order
@ -416,6 +438,16 @@ pub mod diagnostics {
}
}
#[cfg(test)]
impl Permission {
pub fn is_reserved_with_conflicted(&self, expected_conflicted: bool) -> bool {
match self.inner {
Reserved { conflicted, .. } => conflicted == expected_conflicted,
_ => false,
}
}
}
#[cfg(test)]
mod propagation_optimization_checks {
pub use super::*;
@ -424,9 +456,10 @@ mod propagation_optimization_checks {
impl Exhaustive for PermissionPriv {
fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
Box::new(
vec![Active, Frozen, Disabled]
.into_iter()
.chain(bool::exhaustive().map(|ty_is_freeze| Reserved { ty_is_freeze })),
vec![Active, Frozen, Disabled].into_iter().chain(
<[bool; 2]>::exhaustive()
.map(|[ty_is_freeze, conflicted]| Reserved { ty_is_freeze, conflicted }),
),
)
}
}

View File

@ -282,6 +282,113 @@ enum ContinueTraversal {
SkipChildren,
}
/// Stack of nodes left to explore in a tree traversal.
struct TreeVisitorStack<NodeApp, ErrHandler> {
/// Identifier of the original access.
initial: UniIndex,
/// Function to apply to each tag.
f_propagate: NodeApp,
/// Handler to add the required context to diagnostics.
err_builder: ErrHandler,
/// Mutable state of the visit: the tags left to handle.
/// Every tag pushed should eventually be handled,
/// and the precise order is relevant for diagnostics.
stack: Vec<(UniIndex, AccessRelatedness)>,
}
impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitorStack<NodeApp, ErrHandler>
where
NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
{
/// Apply the function to the current `tag`, and push its children
/// to the stack of future tags to visit.
fn exec_and_visit(
&mut self,
this: &mut TreeVisitor<'_>,
idx: UniIndex,
exclude: Option<UniIndex>,
rel_pos: AccessRelatedness,
) -> Result<(), OutErr> {
// 1. apply the propagation function
let node = this.nodes.get_mut(idx).unwrap();
let recurse =
(self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos })
.map_err(|error_kind| {
(self.err_builder)(ErrHandlerArgs {
error_kind,
conflicting_info: &this.nodes.get(idx).unwrap().debug_info,
accessed_info: &this.nodes.get(self.initial).unwrap().debug_info,
})
})?;
let node = this.nodes.get(idx).unwrap();
// 2. add the children to the stack for future traversal
if matches!(recurse, ContinueTraversal::Recurse) {
let general_child_rel = rel_pos.for_child();
for &child in node.children.iter() {
// Some child might be excluded from here and handled separately,
// e.g. the initially accessed tag.
if Some(child) != exclude {
// We should still ensure that if we don't skip the initially accessed
// it will receive the proper `AccessRelatedness`.
let this_child_rel = if child == self.initial {
AccessRelatedness::This
} else {
general_child_rel
};
self.stack.push((child, this_child_rel));
}
}
}
Ok(())
}
fn new(initial: UniIndex, f_propagate: NodeApp, err_builder: ErrHandler) -> Self {
Self { initial, f_propagate, err_builder, stack: Vec::new() }
}
/// Finish the exploration by applying `exec_and_visit` until
/// the stack is empty.
fn finish(&mut self, visitor: &mut TreeVisitor<'_>) -> Result<(), OutErr> {
while let Some((idx, rel_pos)) = self.stack.pop() {
self.exec_and_visit(visitor, idx, /* no children to exclude */ None, rel_pos)?;
}
Ok(())
}
/// Push all ancestors to the exploration stack in order of nearest ancestor
/// towards the top.
fn push_and_visit_strict_ancestors(
&mut self,
visitor: &mut TreeVisitor<'_>,
) -> Result<(), OutErr> {
let mut path_ascend = Vec::new();
// First climb to the root while recording the path
let mut curr = self.initial;
while let Some(ancestor) = visitor.nodes.get(curr).unwrap().parent {
path_ascend.push((ancestor, curr));
curr = ancestor;
}
// Then descend:
// - execute f_propagate on each node
// - record children in visit
while let Some((ancestor, next_in_path)) = path_ascend.pop() {
// Explore ancestors in descending order.
// `next_in_path` is excluded from the recursion because it
// will be the `ancestor` of the next iteration.
// It also needs a different `AccessRelatedness` than the other
// children of `ancestor`.
self.exec_and_visit(
visitor,
ancestor,
Some(next_in_path),
AccessRelatedness::StrictChildAccess,
)?;
}
Ok(())
}
}
impl<'tree> TreeVisitor<'tree> {
// Applies `f_propagate` to every vertex of the tree top-down in the following order: first
// all ancestors of `start`, then `start` itself, then children of `start`, then the rest.
@ -298,107 +405,40 @@ impl<'tree> TreeVisitor<'tree> {
start: BorTag,
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
) -> Result<(), OutErr>
where {
struct TreeVisitAux<NodeApp, ErrHandler> {
accessed_tag: UniIndex,
f_propagate: NodeApp,
err_builder: ErrHandler,
stack: Vec<(UniIndex, AccessRelatedness)>,
}
impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitAux<NodeApp, ErrHandler>
where
NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
{
fn pop(&mut self) -> Option<(UniIndex, AccessRelatedness)> {
self.stack.pop()
}
/// Apply the function to the current `tag`, and push its children
/// to the stack of future tags to visit.
fn exec_and_visit(
&mut self,
this: &mut TreeVisitor<'_>,
tag: UniIndex,
exclude: Option<UniIndex>,
rel_pos: AccessRelatedness,
) -> Result<(), OutErr> {
// 1. apply the propagation function
let node = this.nodes.get_mut(tag).unwrap();
let recurse =
(self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(tag), rel_pos })
.map_err(|error_kind| {
(self.err_builder)(ErrHandlerArgs {
error_kind,
conflicting_info: &this.nodes.get(tag).unwrap().debug_info,
accessed_info: &this
.nodes
.get(self.accessed_tag)
.unwrap()
.debug_info,
})
})?;
let node = this.nodes.get(tag).unwrap();
// 2. add the children to the stack for future traversal
if matches!(recurse, ContinueTraversal::Recurse) {
let child_rel = rel_pos.for_child();
for &child in node.children.iter() {
// some child might be excluded from here and handled separately
if Some(child) != exclude {
self.stack.push((child, child_rel));
}
}
}
Ok(())
}
}
) -> Result<(), OutErr> {
let start_idx = self.tag_mapping.get(&start).unwrap();
let mut stack =
TreeVisitAux { accessed_tag: start_idx, f_propagate, err_builder, stack: Vec::new() };
{
let mut path_ascend = Vec::new();
// First climb to the root while recording the path
let mut curr = start_idx;
while let Some(ancestor) = self.nodes.get(curr).unwrap().parent {
path_ascend.push((ancestor, curr));
curr = ancestor;
}
// Then descend:
// - execute f_propagate on each node
// - record children in visit
while let Some((ancestor, next_in_path)) = path_ascend.pop() {
// Explore ancestors in descending order.
// `next_in_path` is excluded from the recursion because it
// will be the `ancestor` of the next iteration.
// It also needs a different `AccessRelatedness` than the other
// children of `ancestor`.
stack.exec_and_visit(
&mut self,
ancestor,
Some(next_in_path),
AccessRelatedness::StrictChildAccess,
)?;
}
};
// All (potentially zero) ancestors have been explored, call f_propagate on start
stack.exec_and_visit(&mut self, start_idx, None, AccessRelatedness::This)?;
// up to this point we have never popped from `stack`, hence if the
// path to the root is `root = p(n) <- p(n-1)... <- p(1) <- p(0) = start`
// then now `stack` contains
// `[<children(p(n)) except p(n-1)> ... <children(p(1)) except p(0)> <children(p(0))>]`,
// all of which are for now unexplored.
// This is the starting point of a standard DFS which will thus
// explore all non-ancestors of `start` in the following order:
// - all descendants of `start`;
// - then the unexplored descendants of `parent(start)`;
// ...
// - until finally the unexplored descendants of `root`.
while let Some((tag, rel_pos)) = stack.pop() {
stack.exec_and_visit(&mut self, tag, None, rel_pos)?;
}
Ok(())
let mut stack = TreeVisitorStack::new(start_idx, f_propagate, err_builder);
stack.push_and_visit_strict_ancestors(&mut self)?;
// All (potentially zero) ancestors have been explored,
// it's time to explore the `start` tag.
stack.exec_and_visit(
&mut self,
start_idx,
/* no children to exclude */ None,
AccessRelatedness::This,
)?;
// Then finish with a normal DFS.
stack.finish(&mut self)
}
// Applies `f_propagate` to every non-child vertex of the tree (ancestors first).
//
// `f_propagate` should follow the following format: for a given `Node` it updates its
// `Permission` depending on the position relative to `start` (given by an
// `AccessRelatedness`).
// It outputs whether the tree traversal for this subree should continue or not.
fn traverse_nonchildren<InnErr, OutErr>(
mut self,
start: BorTag,
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
) -> Result<(), OutErr> {
let start_idx = self.tag_mapping.get(&start).unwrap();
let mut stack = TreeVisitorStack::new(start_idx, f_propagate, err_builder);
stack.push_and_visit_strict_ancestors(&mut self)?;
// We *don't* visit the `start` tag, and we don't push its children.
// Only finish the DFS with the cousins.
stack.finish(&mut self)
}
}
@ -482,7 +522,7 @@ impl<'tcx> Tree {
self.perform_access(
AccessKind::Write,
tag,
access_range,
Some(access_range),
global,
span,
diagnostics::AccessCause::Dealloc,
@ -520,6 +560,11 @@ impl<'tcx> Tree {
/// Map the per-node and per-location `LocationState::perform_access`
/// to each location of `access_range`, on every tag of the allocation.
///
/// If `access_range` is `None`, this is interpreted as the special
/// access that is applied on protector release:
/// - the access will be applied only to initialized locations of the allocation,
/// - and it will not be visible to children.
///
/// `LocationState::perform_access` will take care of raising transition
/// errors and updating the `initialized` status of each location,
/// this traversal adds to that:
@ -530,56 +575,105 @@ impl<'tcx> Tree {
&mut self,
access_kind: AccessKind,
tag: BorTag,
access_range: AllocRange,
access_range: Option<AllocRange>,
global: &GlobalState,
span: Span, // diagnostics
access_cause: diagnostics::AccessCause, // diagnostics
) -> InterpResult<'tcx> {
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) {
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
.traverse_parents_this_children_others(
tag,
|args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> {
let NodeAppArgs { node, mut perm, rel_pos } = args;
use std::ops::Range;
// Performs the per-node work:
// - insert the permission if it does not exist
// - perform the access
// - record the transition
// to which some optimizations are added:
// - skip the traversal of the children in some cases
// - do not record noop transitions
//
// `perms_range` is only for diagnostics (it is the range of
// the `RangeMap` on which we are currently working).
let node_app = |perms_range: Range<u64>,
args: NodeAppArgs<'_>|
-> Result<ContinueTraversal, TransitionError> {
let NodeAppArgs { node, mut perm, rel_pos } = args;
let old_state =
perm.or_insert_with(|| LocationState::new(node.default_initial_perm));
let old_state = perm.or_insert(LocationState::new(node.default_initial_perm));
match old_state.skip_if_known_noop(access_kind, rel_pos) {
ContinueTraversal::SkipChildren =>
return Ok(ContinueTraversal::SkipChildren),
_ => {}
}
match old_state.skip_if_known_noop(access_kind, rel_pos) {
ContinueTraversal::SkipChildren => return Ok(ContinueTraversal::SkipChildren),
_ => {}
}
let protected = global.borrow().protected_tags.contains_key(&node.tag);
let transition =
old_state.perform_access(access_kind, rel_pos, protected)?;
let protected = global.borrow().protected_tags.contains_key(&node.tag);
let transition = old_state.perform_access(access_kind, rel_pos, protected)?;
// Record the event as part of the history
if !transition.is_noop() {
node.debug_info.history.push(diagnostics::Event {
transition,
is_foreign: rel_pos.is_foreign(),
access_cause,
access_range,
transition_range: perms_range.clone(),
span,
});
}
Ok(ContinueTraversal::Recurse)
},
|args: ErrHandlerArgs<'_, TransitionError>| -> InterpError<'tcx> {
let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args;
TbError {
conflicting_info,
access_cause,
error_offset: perms_range.start,
error_kind,
accessed_info,
}
.build()
},
)?;
// Record the event as part of the history
if !transition.is_noop() {
node.debug_info.history.push(diagnostics::Event {
transition,
is_foreign: rel_pos.is_foreign(),
access_cause,
access_range,
transition_range: perms_range.clone(),
span,
});
}
Ok(ContinueTraversal::Recurse)
};
// Error handler in case `node_app` goes wrong.
// Wraps the faulty transition in more context for diagnostics.
let err_handler = |perms_range: Range<u64>,
args: ErrHandlerArgs<'_, TransitionError>|
-> InterpError<'tcx> {
let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args;
TbError {
conflicting_info,
access_cause,
error_offset: perms_range.start,
error_kind,
accessed_info,
}
.build()
};
if let Some(access_range) = access_range {
// Default branch: this is a "normal" access through a known range.
// We iterate over affected locations and traverse the tree for each of them.
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size)
{
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
.traverse_parents_this_children_others(
tag,
|args| node_app(perms_range.clone(), args),
|args| err_handler(perms_range.clone(), args),
)?;
}
} else {
// This is a special access through the entire allocation.
// It actually only affects `initialized` locations, so we need
// to filter on those before initiating the traversal.
//
// In addition this implicit access should not be visible to children,
// thus the use of `traverse_nonchildren`.
// See the test case `returned_mut_is_usable` from
// `tests/pass/tree_borrows/tree-borrows.rs` for an example of
// why this is important.
for (perms_range, perms) in self.rperms.iter_mut_all() {
let idx = self.tag_mapping.get(&tag).unwrap();
// Only visit initialized permissions
if let Some(p) = perms.get(idx) && p.initialized {
TreeVisitor {
nodes: &mut self.nodes,
tag_mapping: &self.tag_mapping,
perms,
}
.traverse_nonchildren(
tag,
|args| node_app(perms_range.clone(), args),
|args| err_handler(perms_range.clone(), args),
)?;
}
}
}
Ok(())
}

View File

@ -302,6 +302,9 @@ mod spurious_read {
Ok(Self { state, prot: self.prot })
}
/// Remove the protector.
/// This does not perform the implicit read on function exit because
/// `LocStateProt` does not have enough context to apply its effect.
fn end_protector(&self) -> Self {
Self { prot: false, state: self.state }
}
@ -351,7 +354,8 @@ mod spurious_read {
}
/// Perform a read on the given pointer if its state is `initialized`.
/// Must be called just after reborrowing a pointer.
/// Must be called just after reborrowing a pointer, and just after
/// removing a protector.
fn read_if_initialized(self, ptr: PtrSelector) -> Result<Self, ()> {
let initialized = match ptr {
PtrSelector::X => self.x.state.initialized,
@ -368,14 +372,16 @@ mod spurious_read {
}
}
/// Remove the protector of `x`, including the implicit read on function exit.
fn end_protector_x(self) -> Result<Self, ()> {
let x = self.x.end_protector();
Ok(Self { x, ..self })
Self { x, ..self }.read_if_initialized(PtrSelector::X)
}
/// Remove the protector of `y`, including the implicit read on function exit.
fn end_protector_y(self) -> Result<Self, ()> {
let y = self.y.end_protector();
Ok(Self { y, ..self })
Self { y, ..self }.read_if_initialized(PtrSelector::Y)
}
fn retag_y(self, new_y: LocStateProt) -> Result<Self, ()> {
@ -504,11 +510,9 @@ mod spurious_read {
}
#[test]
#[should_panic]
// This is why `Reserved -> Frozen` on foreign read for protected references
// prevents the insertion of spurious reads: the transition can cause UB in the target
// later down the line.
fn reserved_frozen_protected_distinguishable() {
// `Reserved(aliased=false)` and `Reserved(aliased=true)` are properly indistinguishable
// under the conditions where we want to insert a spurious read.
fn reserved_aliased_protected_indistinguishable() {
let source = LocStateProtPair {
xy_rel: RelPosXY::MutuallyForeign,
x: LocStateProt {
@ -522,8 +526,8 @@ mod spurious_read {
};
let acc = TestAccess { ptr: PtrSelector::X, kind: AccessKind::Read };
let target = source.clone().perform_test_access(&acc).unwrap();
assert!(source.y.state.permission.is_reserved(None));
assert!(target.y.state.permission.is_frozen());
assert!(source.y.state.permission.is_reserved_with_conflicted(false));
assert!(target.y.state.permission.is_reserved_with_conflicted(true));
assert!(!source.distinguishable::<(), ()>(&target))
}
@ -599,7 +603,6 @@ mod spurious_read {
}
#[test]
#[should_panic]
/// For each of the patterns described above, execute it once
/// as-is, and once with a spurious read inserted. Report any UB
/// in the target but not in the source.

View File

@ -212,12 +212,9 @@ impl<'a, V> UniValMap<V> {
impl<'a, V> UniEntry<'a, V> {
/// Insert in the map and get the value.
pub fn or_insert_with<F>(&mut self, default: F) -> &mut V
where
F: FnOnce() -> V,
{
pub fn or_insert(&mut self, default: V) -> &mut V {
if self.inner.is_none() {
*self.inner = Some(default());
*self.inner = Some(default);
}
self.inner.as_mut().unwrap()
}

View File

@ -960,7 +960,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
self.check_abi(abi, exp_abi)?;
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
// We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased
// We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
// performance. Note that this means we won't catch any undefined behavior in
// compiler-builtins when running other crates, but Miri can still be run on
// compiler-builtins itself (or any crate that uses it as a normal dependency)

View File

@ -8,6 +8,7 @@
#![feature(yeet_expr)]
#![feature(nonzero_ops)]
#![feature(round_ties_even)]
#![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(trait_upcasting)]
// Configure clippy and other lints
@ -86,9 +87,8 @@ pub use rustc_const_eval::interpret::*;
// Resolve ambiguity.
pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _};
pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _};
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
pub use crate::shims::foreign_items::EvalContextExt as _;
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
pub use crate::shims::intrinsics::EvalContextExt as _;
pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};

View File

@ -707,11 +707,10 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
);
}
"android" => {
// "signal"
// "signal" -- just needs a non-zero pointer value (function does not even get called),
// but we arrange for this to be callable anyway (it will then do nothing).
let layout = this.machine.layouts.const_raw_ptr;
let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)?
.expect("`signal` must be an actual dlsym on android");
let ptr = this.fn_ptr(FnVal::Other(dlsym));
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
Self::alloc_extern_static(this, "signal", val)?;
// A couple zero-initialized pointer-sized extern statics.
@ -867,7 +866,7 @@ impl<'mir, 'tcx> MiriInterpCxExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {
/// Machine hook implementations.
impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
type MemoryKind = MiriMemoryKind;
type ExtraFnVal = Dlsym;
type ExtraFnVal = DynSym;
type FrameExtra = FrameExtra<'tcx>;
type AllocExtra = AllocExtra<'tcx>;
@ -939,15 +938,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
#[inline(always)]
fn call_extra_fn(
ecx: &mut MiriInterpCx<'mir, 'tcx>,
fn_val: Dlsym,
fn_val: DynSym,
abi: Abi,
args: &[FnArg<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
_unwind: mir::UnwindAction,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
ecx.call_dlsym(fn_val, abi, &args, dest, ret)
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
}
#[inline(always)]
@ -1275,19 +1274,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ecx: &mut InterpCx<'mir, 'tcx, Self>,
place: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx> {
// We do need to write `uninit` so that even after the call ends, the former contents of
// this place cannot be observed any more.
ecx.write_uninit(place)?;
// 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.
if ecx.machine.borrow_tracker.is_some() {
let protected_place = if ecx.machine.borrow_tracker.is_some() {
// Have to do `to_op` first because a `Place::Local` doesn't imply the local doesn't have an address.
if let Either::Left(place) = ecx.place_to_op(place)?.as_mplace_or_imm() {
ecx.protect_place(&place)?;
ecx.protect_place(&place)?.into()
} else {
// Locals that don't have their address taken are as protected as they can ever be.
place.clone()
}
}
} else {
// No borrow tracker.
place.clone()
};
// We do need to write `uninit` so that even after the call ends, the former contents of
// this place cannot be observed any more. We do the write after retagging so that for
// Tree Borrows, this is considered to activate the new tag.
ecx.write_uninit(&protected_place)?;
// Now we throw away the protected place, ensuring its tag is never used again.
Ok(())
}
@ -1382,8 +1387,34 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
) -> InterpResult<'tcx> {
// We want this *before* the return value copy, because the return place itself is protected
// until we do `end_call` here.
if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().end_call(&frame.extra);
if let Some(global_borrow_tracker) = &ecx.machine.borrow_tracker {
// The body of this loop needs `global_borrow_tracker` immutably
// so we can't move this code inside the following `end_call`.
for (alloc_id, tag) in &frame
.extra
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
.protected_tags
{
// Just because the tag is protected doesn't guarantee that
// the allocation still exists (weak protectors allow deallocations)
// so we must check that the allocation exists.
// If it does exist, then we have the guarantee that the
// pointer is readable, and the implicit read access inserted
// will never cause UB on the pointer itself.
let (_, _, kind) = ecx.get_alloc_info(*alloc_id);
if matches!(kind, AllocKind::LiveData) {
let alloc_extra = ecx.get_alloc_extra(*alloc_id).unwrap();
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
alloc_borrow_tracker.release_protector(
&ecx.machine,
global_borrow_tracker,
*tag,
)?;
}
}
global_borrow_tracker.borrow_mut().end_call(&frame.extra);
}
Ok(())
}

View File

@ -1,48 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use crate::helpers::target_os_is_unix;
use crate::*;
use shims::unix::dlsym as unix;
use shims::windows::dlsym as windows;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
Posix(unix::Dlsym),
Windows(windows::Dlsym),
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
let name = &*String::from_utf8_lossy(name);
Ok(match target_os {
target if target_os_is_unix(target) =>
unix::Dlsym::from_str(name, target)?.map(Dlsym::Posix),
"windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows),
os => bug!("dlsym not implemented for target_os {}", os),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
match dlsym {
Dlsym::Posix(dlsym) =>
unix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret),
Dlsym::Windows(dlsym) =>
windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret),
}
}
}

View File

@ -6,7 +6,7 @@ use rustc_apfloat::Float;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_hir::{
def::DefKind,
def_id::{CrateNum, DefId, LOCAL_CRATE},
def_id::{CrateNum, LOCAL_CRATE},
};
use rustc_middle::middle::{
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
@ -25,120 +25,141 @@ use super::backtrace::EvalContextExt as _;
use crate::helpers::target_os_is_unix;
use crate::*;
/// Returned by `emulate_foreign_item_by_name`.
pub enum EmulateByNameResult<'mir, 'tcx> {
/// Type of dynamic symbols (for `dlsym` et al)
#[derive(Debug, Copy, Clone)]
pub struct DynSym(Symbol);
#[allow(clippy::should_implement_trait)]
impl DynSym {
pub fn from_str(name: &str) -> Self {
DynSym(Symbol::intern(name))
}
}
/// Returned by `emulate_foreign_item_inner`.
pub enum EmulateForeignItemResult {
/// The caller is expected to jump to the return block.
NeedsJumping,
/// Jumping has already been taken care of.
AlreadyJumped,
/// A MIR body has been found for the function.
MirBody(&'mir mir::Body<'tcx>, ty::Instance<'tcx>),
/// The item is not supported.
NotSupported,
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Returns the minimum alignment for the target architecture for allocations of the given size.
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
let this = self.eval_context_ref();
// List taken from `library/std/src/sys/common/alloc.rs`.
// This list should be kept in sync with the one from libstd.
let min_align = match this.tcx.sess.target.arch.as_ref() {
"x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
"x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
16,
arch => bug!("unsupported target architecture for malloc: `{}`", arch),
/// Emulates calling a foreign item, failing if the item is not supported.
/// This function will handle `goto_block` if needed.
/// Returns Ok(None) if the foreign item was completely handled
/// by this function.
/// Returns Ok(Some(body)) if processing the foreign item
/// is delegated to another function.
fn emulate_foreign_item(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
let this = self.eval_context_mut();
let tcx = this.tcx.tcx;
// First: functions that diverge.
let ret = match ret {
None =>
match link_name.as_str() {
"miri_start_panic" => {
// `check_shim` happens inside `handle_miri_start_panic`.
this.handle_miri_start_panic(abi, link_name, args, unwind)?;
return Ok(None);
}
// This matches calls to the foreign item `panic_impl`.
// The implementation is provided by the function with the `#[panic_handler]` attribute.
"panic_impl" => {
// We don't use `check_shim` here because we are just forwarding to the lang
// item. Argument count checking will be performed when the returned `Body` is
// called.
this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
return Ok(Some((
this.load_mir(panic_impl_instance.def, None)?,
panic_impl_instance,
)));
}
#[rustfmt::skip]
| "exit"
| "ExitProcess"
=> {
let exp_abi = if link_name.as_str() == "exit" {
Abi::C { unwind: false }
} else {
Abi::System { unwind: false }
};
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
"abort" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
}
_ => {
if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body));
}
this.handle_unsupported(format!(
"can't call (diverging) foreign function: {link_name}"
))?;
return Ok(None);
}
},
Some(p) => p,
};
// Windows always aligns, even small allocations.
// Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
// But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
if kind == MiriMemoryKind::WinHeap || size >= min_align {
return Align::from_bytes(min_align).unwrap();
}
// We have `size < min_align`. Round `size` *down* to the next power of two and use that.
fn prev_power_of_two(x: u64) -> u64 {
let next_pow2 = x.next_power_of_two();
if next_pow2 == x {
// x *is* a power of two, just use that.
x
} else {
// x is between two powers, so next = 2*prev.
next_pow2 / 2
// Second: functions that return immediately.
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
EmulateForeignItemResult::NeedsJumping => {
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
}
EmulateForeignItemResult::AlreadyJumped => (),
EmulateForeignItemResult::NotSupported => {
if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body));
}
this.handle_unsupported(format!(
"can't call foreign function `{link_name}` on OS `{os}`",
os = this.tcx.sess.target.os,
))?;
return Ok(None);
}
}
Align::from_bytes(prev_power_of_two(size)).unwrap()
Ok(None)
}
fn malloc(
/// Emulates a call to a `DynSym`.
fn emulate_dyn_sym(
&mut self,
size: u64,
zero_init: bool,
kind: MiriMemoryKind,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
let this = self.eval_context_mut();
if size == 0 {
Ok(Pointer::null())
} else {
let align = this.min_align(size, kind);
let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
if zero_init {
// We just allocated this, the access is definitely in-bounds and fits into our address space.
this.write_bytes_ptr(
ptr.into(),
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
)
.unwrap();
}
Ok(ptr.into())
}
}
fn free(
&mut self,
ptr: Pointer<Option<Provenance>>,
kind: MiriMemoryKind,
sym: DynSym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
if !this.ptr_is_null(ptr)? {
this.deallocate_ptr(ptr, None, kind.into())?;
}
let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?;
assert!(res.is_none(), "DynSyms that delegate are not supported");
Ok(())
}
fn realloc(
&mut self,
old_ptr: Pointer<Option<Provenance>>,
new_size: u64,
kind: MiriMemoryKind,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
let this = self.eval_context_mut();
let new_align = this.min_align(new_size, kind);
if this.ptr_is_null(old_ptr)? {
if new_size == 0 {
Ok(Pointer::null())
} else {
let new_ptr =
this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?;
Ok(new_ptr.into())
}
} else {
if new_size == 0 {
this.deallocate_ptr(old_ptr, None, kind.into())?;
Ok(Pointer::null())
} else {
let new_ptr = this.reallocate_ptr(
old_ptr,
None,
Size::from_bytes(new_size),
new_align,
kind.into(),
)?;
Ok(new_ptr.into())
}
}
}
/// Lookup the body of a function that has `link_name` as the symbol name.
fn lookup_exported_symbol(
&mut self,
@ -233,6 +254,78 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
fn malloc(
&mut self,
size: u64,
zero_init: bool,
kind: MiriMemoryKind,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
let this = self.eval_context_mut();
if size == 0 {
Ok(Pointer::null())
} else {
let align = this.min_align(size, kind);
let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
if zero_init {
// We just allocated this, the access is definitely in-bounds and fits into our address space.
this.write_bytes_ptr(
ptr.into(),
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
)
.unwrap();
}
Ok(ptr.into())
}
}
fn free(
&mut self,
ptr: Pointer<Option<Provenance>>,
kind: MiriMemoryKind,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
if !this.ptr_is_null(ptr)? {
this.deallocate_ptr(ptr, None, kind.into())?;
}
Ok(())
}
fn realloc(
&mut self,
old_ptr: Pointer<Option<Provenance>>,
new_size: u64,
kind: MiriMemoryKind,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
let this = self.eval_context_mut();
let new_align = this.min_align(new_size, kind);
if this.ptr_is_null(old_ptr)? {
if new_size == 0 {
Ok(Pointer::null())
} else {
let new_ptr =
this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?;
Ok(new_ptr.into())
}
} else {
if new_size == 0 {
this.deallocate_ptr(old_ptr, None, kind.into())?;
Ok(Pointer::null())
} else {
let new_ptr = this.reallocate_ptr(
old_ptr,
None,
Size::from_bytes(new_size),
new_align,
kind.into(),
)?;
Ok(new_ptr.into())
}
}
}
}
impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Read bytes from a `(ptr, len)` argument
fn read_byte_slice<'i>(&'i self, bytes: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, &'i [u8]>
where
@ -246,115 +339,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(bytes)
}
/// Emulates calling a foreign item, failing if the item is not supported.
/// This function will handle `goto_block` if needed.
/// Returns Ok(None) if the foreign item was completely handled
/// by this function.
/// Returns Ok(Some(body)) if processing the foreign item
/// is delegated to another function.
fn emulate_foreign_item(
&mut self,
def_id: DefId,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
let this = self.eval_context_mut();
let link_name = this.item_link_name(def_id);
let tcx = this.tcx.tcx;
// First: functions that diverge.
let ret = match ret {
None =>
match link_name.as_str() {
"miri_start_panic" => {
// `check_shim` happens inside `handle_miri_start_panic`.
this.handle_miri_start_panic(abi, link_name, args, unwind)?;
return Ok(None);
}
// This matches calls to the foreign item `panic_impl`.
// The implementation is provided by the function with the `#[panic_handler]` attribute.
"panic_impl" => {
// We don't use `check_shim` here because we are just forwarding to the lang
// item. Argument count checking will be performed when the returned `Body` is
// called.
this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
return Ok(Some((
this.load_mir(panic_impl_instance.def, None)?,
panic_impl_instance,
)));
}
#[rustfmt::skip]
| "exit"
| "ExitProcess"
=> {
let exp_abi = if link_name.as_str() == "exit" {
Abi::C { unwind: false }
} else {
Abi::System { unwind: false }
};
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
"abort" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
}
_ => {
if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body));
}
this.handle_unsupported(format!(
"can't call (diverging) foreign function: {link_name}"
))?;
return Ok(None);
}
},
Some(p) => p,
/// Returns the minimum alignment for the target architecture for allocations of the given size.
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
let this = self.eval_context_ref();
// List taken from `library/std/src/sys/common/alloc.rs`.
// This list should be kept in sync with the one from libstd.
let min_align = match this.tcx.sess.target.arch.as_ref() {
"x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
"x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
16,
arch => bug!("unsupported target architecture for malloc: `{}`", arch),
};
// Second: functions that return immediately.
match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? {
EmulateByNameResult::NeedsJumping => {
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
}
EmulateByNameResult::AlreadyJumped => (),
EmulateByNameResult::MirBody(mir, instance) => return Ok(Some((mir, instance))),
EmulateByNameResult::NotSupported => {
if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body));
}
this.handle_unsupported(format!(
"can't call foreign function `{link_name}` on OS `{os}`",
os = this.tcx.sess.target.os,
))?;
return Ok(None);
// Windows always aligns, even small allocations.
// Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
// But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
if kind == MiriMemoryKind::WinHeap || size >= min_align {
return Align::from_bytes(min_align).unwrap();
}
// We have `size < min_align`. Round `size` *down* to the next power of two and use that.
fn prev_power_of_two(x: u64) -> u64 {
let next_pow2 = x.next_power_of_two();
if next_pow2 == x {
// x *is* a power of two, just use that.
x
} else {
// x is between two powers, so next = 2*prev.
next_pow2 / 2
}
}
Ok(None)
Align::from_bytes(prev_power_of_two(size)).unwrap()
}
/// Emulates calling the internal __rust_* allocator functions
fn emulate_allocator(
&mut self,
default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
// in real code, this symbol does not exist without an allocator
return Ok(EmulateByNameResult::NotSupported);
return Ok(EmulateForeignItemResult::NotSupported);
};
match allocator_kind {
@ -364,23 +389,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// and not execute any Miri shim. Somewhat unintuitively doing so is done
// by returning `NotSupported`, which triggers the `lookup_exported_symbol`
// fallback case in `emulate_foreign_item`.
return Ok(EmulateByNameResult::NotSupported);
return Ok(EmulateForeignItemResult::NotSupported);
}
AllocatorKind::Default => {
default(this)?;
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}
}
/// Emulates calling a foreign item using its name.
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// First deal with any external C functions in linked .so file.
@ -391,7 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// by the specified `.so` file; we should continue and check if it corresponds to
// a provided shim.
if this.call_external_c_fct(link_name, dest, args)? {
return Ok(EmulateByNameResult::NeedsJumping);
return Ok(EmulateForeignItemResult::NeedsJumping);
}
}
@ -591,7 +615,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"__rust_alloc" => return this.emulate_allocator(default),
"miri_alloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
return Ok(EmulateForeignItemResult::NeedsJumping);
}
_ => unreachable!(),
}
@ -651,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
"miri_dealloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
return Ok(EmulateForeignItemResult::NeedsJumping);
}
_ => unreachable!(),
}
@ -1045,19 +1069,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ =>
return match this.tcx.sess.target.os.as_ref() {
target_os if target_os_is_unix(target_os) =>
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest,
),
"windows" =>
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest,
),
_ => Ok(EmulateByNameResult::NotSupported),
_ => Ok(EmulateForeignItemResult::NotSupported),
},
};
// We only fall through to here if we did *not* hit the `_` arm above,
// i.e., if we actually emulated the function with one of the shims.
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
/// Check some basic requirements for this allocation request:

View File

@ -32,28 +32,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
assert_eq!(dest_len, op_len);
#[derive(Copy, Clone)]
enum HostFloatOp {
Ceil,
Floor,
Round,
Trunc,
Sqrt,
}
#[derive(Copy, Clone)]
enum Op {
MirOp(mir::UnOp),
Abs,
HostOp(HostFloatOp),
Sqrt,
Round(rustc_apfloat::Round),
}
let which = match intrinsic_name {
"neg" => Op::MirOp(mir::UnOp::Neg),
"fabs" => Op::Abs,
"ceil" => Op::HostOp(HostFloatOp::Ceil),
"floor" => Op::HostOp(HostFloatOp::Floor),
"round" => Op::HostOp(HostFloatOp::Round),
"trunc" => Op::HostOp(HostFloatOp::Trunc),
"fsqrt" => Op::HostOp(HostFloatOp::Sqrt),
"fsqrt" => Op::Sqrt,
"ceil" => Op::Round(rustc_apfloat::Round::TowardPositive),
"floor" => Op::Round(rustc_apfloat::Round::TowardNegative),
"round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
"trunc" => Op::Round(rustc_apfloat::Round::TowardZero),
_ => unreachable!(),
};
@ -73,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
}
}
Op::HostOp(host_op) => {
Op::Sqrt => {
let ty::Float(float_ty) = op.layout.ty.kind() else {
span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
};
@ -81,28 +74,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match float_ty {
FloatTy::F32 => {
let f = f32::from_bits(op.to_scalar().to_u32()?);
let res = match host_op {
HostFloatOp::Ceil => f.ceil(),
HostFloatOp::Floor => f.floor(),
HostFloatOp::Round => f.round(),
HostFloatOp::Trunc => f.trunc(),
HostFloatOp::Sqrt => f.sqrt(),
};
let res = f.sqrt();
Scalar::from_u32(res.to_bits())
}
FloatTy::F64 => {
let f = f64::from_bits(op.to_scalar().to_u64()?);
let res = match host_op {
HostFloatOp::Ceil => f.ceil(),
HostFloatOp::Floor => f.floor(),
HostFloatOp::Round => f.round(),
HostFloatOp::Trunc => f.trunc(),
HostFloatOp::Sqrt => f.sqrt(),
};
let res = f.sqrt();
Scalar::from_u64(res.to_bits())
}
}
}
Op::Round(rounding) => {
let ty::Float(float_ty) = op.layout.ty.kind() else {
span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
};
match float_ty {
FloatTy::F32 => {
let f = op.to_scalar().to_f32()?;
let res = f.round_to_integral(rounding).value;
Scalar::from_f32(res)
}
FloatTy::F64 => {
let f = op.to_scalar().to_f64()?;
let res = f.round_to_integral(rounding).value;
Scalar::from_f64(res)
}
}
}
};
this.write_scalar(val, &dest)?;

View File

@ -9,7 +9,6 @@ pub mod unix;
pub mod windows;
mod x86;
pub mod dlsym;
pub mod env;
pub mod os_str;
pub mod panic;
@ -58,7 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// foreign function
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
return this.emulate_foreign_item(instance.def_id(), abi, &args, dest, ret, unwind);
let link_name = this.item_link_name(instance.def_id());
return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
}
// Otherwise, load the MIR.

View File

@ -1,54 +0,0 @@
use rustc_middle::mir;
use crate::helpers::check_arg_count;
use crate::*;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
signal,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"signal" => Some(Dlsym::signal),
"android_set_abort_message" => None,
_ => throw_unsup_format!("unsupported Android dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "android");
match dlsym {
Dlsym::signal => {
if !this.frame_in_std() {
throw_unsup_format!(
"`signal` support is crude and just enough for libstd to work"
);
}
let [_sig, _func] = check_arg_count(args)?;
this.write_null(dest)?;
}
}
log::trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View File

@ -2,25 +2,29 @@ use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
#[allow(unused, clippy::match_single_binding)] // there isn't anything here yet
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
_abi: Abi,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let _this = self.eval_context_mut();
#[allow(clippy::match_single_binding)]
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
match link_name.as_str() {
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
#[allow(unreachable_code)]
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View File

@ -1,55 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::unix::android::dlsym as android;
use shims::unix::freebsd::dlsym as freebsd;
use shims::unix::linux::dlsym as linux;
use shims::unix::macos::dlsym as macos;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
Android(android::Dlsym),
FreeBsd(freebsd::Dlsym),
Linux(linux::Dlsym),
MacOs(macos::Dlsym),
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match target_os {
"android" => android::Dlsym::from_str(name)?.map(Dlsym::Android),
"freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd),
"linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux),
"macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs),
_ => panic!("unsupported Unix OS {target_os}"),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
this.check_abi(abi, Abi::C { unwind: false })?;
match dlsym {
Dlsym::Android(dlsym) =>
android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::FreeBsd(dlsym) =>
freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
}
}
}

View File

@ -1,4 +1,5 @@
use std::ffi::OsStr;
use std::str;
use log::trace;
@ -8,24 +9,48 @@ use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::mem::EvalContextExt as _;
use shims::unix::sync::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
use shims::unix::android::foreign_items as android;
use shims::unix::freebsd::foreign_items as freebsd;
use shims::unix::linux::foreign_items as linux;
use shims::unix::macos::foreign_items as macos;
fn is_dyn_sym(name: &str, target_os: &str) -> bool {
match name {
// Used for tests.
"isatty" => true,
// `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
// well allow it in `dlsym`.
"signal" => true,
// Give specific OSes a chance to allow their symbols.
_ =>
match target_os {
"android" => android::is_dyn_sym(name),
"freebsd" => freebsd::is_dyn_sym(name),
"linux" => linux::is_dyn_sym(name),
"macos" => macos::is_dyn_sym(name),
target_os => panic!("unsupported Unix OS {target_os}"),
},
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
#[rustfmt::skip]
match link_name.as_str() {
// Environment related shims
@ -230,9 +255,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.read_target_usize(handle)?;
let symbol = this.read_pointer(symbol)?;
let symbol_name = this.read_c_str(symbol)?;
if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
let ptr = this.fn_ptr(FnVal::Other(dlsym));
let name = this.read_c_str(symbol)?;
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) {
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
this.write_pointer(ptr, dest)?;
} else {
this.write_null(dest)?;
@ -565,7 +590,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"getuid"
if this.frame_in_std() => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FOr now, just pretend we always have this fixed UID.
// For now, just pretend we always have this fixed UID.
this.write_int(super::UID, dest)?;
}
@ -609,15 +634,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => {
let target_os = &*this.tcx.sess.target.os;
return match target_os {
"android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
_ => Ok(EmulateByNameResult::NotSupported),
"android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
_ => Ok(EmulateForeignItemResult::NotSupported),
};
}
};
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,36 +0,0 @@
use rustc_middle::mir;
use crate::*;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
throw_unsup_format!("unsupported FreeBSD dlsym: {}", name)
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let _ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "freebsd");
match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
}
}

View File

@ -2,19 +2,22 @@ use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::thread::EvalContextExt as _;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
match link_name.as_str() {
// Threading
@ -42,8 +45,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View File

@ -63,7 +63,7 @@ pub trait FileDescriptor: std::fmt::Debug + Any {
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>;
fn is_tty(&self) -> bool {
fn is_tty(&self, _communicate_allowed: bool) -> bool {
false
}
@ -156,8 +156,8 @@ impl FileDescriptor for FileHandle {
Some(self.file.as_raw_fd())
}
fn is_tty(&self) -> bool {
self.file.is_terminal()
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.file.is_terminal()
}
}
@ -188,8 +188,8 @@ impl FileDescriptor for io::Stdin {
Some(libc::STDIN_FILENO)
}
fn is_tty(&self) -> bool {
self.is_terminal()
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
}
@ -225,8 +225,8 @@ impl FileDescriptor for io::Stdout {
Some(libc::STDOUT_FILENO)
}
fn is_tty(&self) -> bool {
self.is_terminal()
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
}
@ -255,8 +255,8 @@ impl FileDescriptor for io::Stderr {
Some(libc::STDERR_FILENO)
}
fn is_tty(&self) -> bool {
self.is_terminal()
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
}
@ -1721,15 +1721,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
// "returns 1 if fd is an open file descriptor referring to a terminal;
// otherwise 0 is returned, and errno is set to indicate the error"
if matches!(this.machine.isolated_op, IsolatedOp::Allow) {
let fd = this.read_scalar(miri_fd)?.to_i32()?;
if this.machine.file_handler.handles.get(&fd).map(|fd| fd.is_tty()) == Some(true) {
let fd = this.read_scalar(miri_fd)?.to_i32()?;
let error = if let Some(fd) = this.machine.file_handler.handles.get(&fd) {
if fd.is_tty(this.machine.communicate()) {
return Ok(Scalar::from_i32(1));
} else {
this.eval_libc("ENOTTY")
}
}
// Fallback when the FD was not found or isolation is enabled.
let enotty = this.eval_libc("ENOTTY");
this.set_last_error(enotty)?;
} else {
// FD does not exist
this.eval_libc("EBADF")
};
this.set_last_error(error)?;
Ok(Scalar::from_i32(0))
}

View File

@ -1,40 +0,0 @@
use rustc_middle::mir;
use crate::*;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"__pthread_get_minstack" => None,
"getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL.
"statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL.
_ => throw_unsup_format!("unsupported Linux dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let _ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "linux");
match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
}
}

View File

@ -4,7 +4,7 @@ use rustc_target::spec::abi::Abi;
use crate::machine::SIGRTMAX;
use crate::machine::SIGRTMIN;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::linux::fd::EvalContextExt as _;
use shims::unix::linux::mem::EvalContextExt as _;
@ -12,18 +12,22 @@ use shims::unix::linux::sync::futex;
use shims::unix::sync::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "getrandom")
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
match link_name.as_str() {
// errno
@ -182,7 +186,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
id => {
this.handle_unsupported(format!("can't execute syscall with ID {id}"))?;
return Ok(EmulateByNameResult::AlreadyJumped);
return Ok(EmulateForeignItemResult::AlreadyJumped);
}
}
}
@ -213,10 +217,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_null(dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
};
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod fd;
pub mod foreign_items;
pub mod mem;

View File

@ -1,52 +0,0 @@
use rustc_middle::mir;
use log::trace;
use crate::*;
use helpers::check_arg_count;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
getentropy,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"getentropy" => Some(Dlsym::getentropy),
_ => throw_unsup_format!("unsupported macOS dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "macos");
match dlsym {
Dlsym::getentropy => {
let [ptr, len] = check_arg_count(args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
this.write_null(dest)?;
}
}
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View File

@ -2,22 +2,26 @@ use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "getentropy")
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
match link_name.as_str() {
// errno
@ -109,6 +113,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(result, dest)?;
}
// Random generation related shims
"getentropy" => {
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
}
// Access to command-line arguments
"_NSGetArgc" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -193,9 +209,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(res, dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
};
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View File

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod foreign_items;
mod fs;

View File

@ -1,82 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use log::trace;
use crate::helpers::check_arg_count;
use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
use crate::shims::windows::sync::EvalContextExt as _;
use crate::*;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
SetThreadDescription,
WaitOnAddress,
WakeByAddressSingle,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"GetSystemTimePreciseAsFileTime" => None,
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
"WaitOnAddress" => Some(Dlsym::WaitOnAddress),
"WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
_ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "windows");
this.check_abi(abi, Abi::System { unwind: false })?;
match dlsym {
Dlsym::SetThreadDescription => {
let [handle, name] = check_arg_count(args)?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
let thread = match Handle::from_scalar(handle, this)? {
Some(Handle::Thread(thread)) => thread,
Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(),
_ => this.invalid_handle("SetThreadDescription")?,
};
this.set_thread_name_wide(thread, &name);
this.write_null(dest)?;
}
Dlsym::WaitOnAddress => {
let [ptr_op, compare_op, size_op, timeout_op] = check_arg_count(args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
Dlsym::WakeByAddressSingle => {
let [ptr_op] = check_arg_count(args)?;
this.WakeByAddressSingle(ptr_op)?;
}
}
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View File

@ -1,27 +1,32 @@
use std::iter;
use std::str;
use rustc_span::Symbol;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
use shims::windows::sync::EvalContextExt as _;
use shims::windows::thread::EvalContextExt as _;
fn is_dyn_sym(name: &str) -> bool {
matches!(name, "SetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle")
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
// Windows API stubs.
// HANDLE = isize
@ -326,6 +331,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.WakeAllConditionVariable(condvar)?;
}
"WaitOnAddress" => {
let [ptr_op, compare_op, size_op, timeout_op] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
"WakeByAddressSingle" => {
let [ptr_op] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.WakeByAddressSingle(ptr_op)?;
}
// Dynamic symbol loading
"GetProcAddress" => {
@ -334,14 +351,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.read_target_isize(hModule)?;
let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
let ptr = this.fn_ptr(FnVal::Other(dlsym));
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) {
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
this.write_pointer(ptr, dest)?;
} else {
this.write_null(dest)?;
}
}
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(Scalar::from_u32(ret), dest)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
dest,
)?;
}
"SetThreadDescription" => {
let [handle, name] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
let thread = match Handle::from_scalar(handle, this)? {
Some(Handle::Thread(thread)) => thread,
Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(),
_ => this.invalid_handle("SetThreadDescription")?,
};
this.set_thread_name_wide(thread, &name);
this.write_null(dest)?;
}
// Miscellaneous
"SystemFunction036" => {
// This is really 'RtlGenRandom'.
@ -456,32 +517,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(Scalar::from_u32(ret), dest)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
dest,
)?;
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"GetProcessHeap" if this.frame_in_std() => {
@ -548,9 +583,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_null(dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod foreign_items;
mod handle;

View File

@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi;
use crate::*;
use helpers::bool_to_simd_element;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
mod sse;
mod sse2;
@ -22,7 +22,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
@ -34,7 +34,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
// https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html
"addcarry.32" | "addcarry.64" => {
if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" {
return Ok(EmulateByNameResult::NotSupported);
return Ok(EmulateForeignItemResult::NotSupported);
}
let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@ -60,7 +60,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
// https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
"subborrow.32" | "subborrow.64" => {
if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" {
return Ok(EmulateByNameResult::NotSupported);
return Ok(EmulateForeignItemResult::NotSupported);
}
let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@ -100,9 +100,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this, link_name, abi, args, dest,
);
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -7,7 +7,7 @@ use rand::Rng as _;
use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -19,7 +19,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap();
@ -141,10 +141,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f32()?;
let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f32()?;
// The difference between the com* and *ucom variants is signaling
// The difference between the com* and ucom* variants is signaling
// of exceptions when either argument is a quiet NaN. We do not
// support accessing the SSE status register from miri (or from Rust,
// for that matter), so we treat equally both variants.
// for that matter), so we treat both variants equally.
let res = match unprefixed_name {
"comieq.ss" | "ucomieq.ss" => left == right,
"comilt.ss" | "ucomilt.ss" => left < right,
@ -228,9 +228,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_scalar(Scalar::from_u32(res), dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -10,7 +10,7 @@ use rustc_target::spec::abi::Abi;
use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -22,7 +22,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap();
@ -637,10 +637,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f64()?;
let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f64()?;
// The difference between the com* and *ucom variants is signaling
// The difference between the com* and ucom* variants is signaling
// of exceptions when either argument is a quiet NaN. We do not
// support accessing the SSE status register from miri (or from Rust,
// for that matter), so we treat equally both variants.
// for that matter), so we treat both variants equally.
let res = match unprefixed_name {
"comieq.sd" | "ucomieq.sd" => left == right,
"comilt.sd" | "ucomilt.sd" => left < right,
@ -797,9 +797,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.yield_active_thread();
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi;
use super::horizontal_bin_op;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -17,7 +17,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse3.").unwrap();
@ -83,8 +83,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
/*nonoverlapping*/ true,
)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -4,7 +4,7 @@ use rustc_target::spec::abi::Abi;
use super::horizontal_bin_op;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -16,7 +16,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.ssse3.").unwrap();
@ -192,8 +192,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_immediate(*res, &dest)?;
}
}
_ => return Ok(EmulateByNameResult::NotSupported),
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateByNameResult::NeedsJumping)
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -2,12 +2,42 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -16,15 +46,24 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.11.1"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytes"
version = "1.3.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
@ -45,9 +84,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.8"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"js-sys",
@ -57,34 +96,37 @@ dependencies = [
]
[[package]]
name = "hermit-abi"
version = "0.2.6"
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "hermit-abi"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "js-sys"
version = "0.3.60"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.139"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "lock_api"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
@ -92,27 +134,32 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.5"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
@ -122,7 +169,7 @@ name = "miri-test-deps"
version = "0.1.0"
dependencies = [
"getrandom 0.1.16",
"getrandom 0.2.8",
"getrandom 0.2.10",
"libc",
"num_cpus",
"page_size",
@ -132,25 +179,34 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.17.0"
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "page_size"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b7663cbd190cfd818d08efa8497f6cd383076688c49a391ef7c0d03cd12b561"
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
dependencies = [
"libc",
"winapi",
@ -168,22 +224,22 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.5"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
"windows-targets",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "ppv-lite86"
@ -193,18 +249,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.60"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@ -236,54 +292,60 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.8",
"getrandom 0.2.10",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.10.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "socket2"
version = "0.4.7"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [
"libc",
"winapi",
"windows-sys",
]
[[package]]
name = "syn"
version = "1.0.107"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -292,14 +354,13 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.24.2"
version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [
"autocfg",
"backtrace",
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"parking_lot",
@ -312,9 +373,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.8.2"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
@ -323,9 +384,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.6"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
@ -341,9 +402,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -351,9 +412,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
@ -366,9 +427,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -376,9 +437,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
@ -389,9 +450,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "winapi"
@ -417,9 +478,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.42.0"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@ -432,42 +502,42 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View File

@ -17,7 +17,7 @@ getrandom = { version = "0.2", features = ["js"] }
rand = { version = "0.8", features = ["small_rng"] }
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
page_size = "0.5"
page_size = "0.6"
tokio = { version = "1.24", features = ["full"] }
[workspace]

View File

@ -93,9 +93,7 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
..Config::rustc(path)
};
let use_std = env::var_os("MIRI_NO_STD").is_none();
if with_dependencies && use_std {
if with_dependencies {
config.dependencies_crate_manifest_path =
Some(Path::new("test_dependencies").join("Cargo.toml"));
let mut builder_args = vec!["run".into()];

View File

@ -5,18 +5,18 @@ LL | *x = 1;
| ^^^^^^ write access through <TAG> is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> has state Frozen which forbids this child write access
= help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> $DIR/aliasing_mut1.rs:LL:CC
|
LL | pub fn safe(x: &mut i32, y: &mut i32) {
| ^
help: the accessed tag <TAG> later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
help: the accessed tag <TAG> later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
--> $DIR/aliasing_mut1.rs:LL:CC
|
LL | pub fn safe(x: &mut i32, y: &mut i32) {
| ^
= help: this transition corresponds to a loss of write permissions
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC
note: inside `main`

View File

@ -5,18 +5,18 @@ LL | *y = 2;
| ^^^^^^ write access through <TAG> is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> has state Frozen which forbids this child write access
= help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> $DIR/aliasing_mut2.rs:LL:CC
|
LL | pub fn safe(x: &i32, y: &mut i32) {
| ^
help: the accessed tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x4]
help: the accessed tag <TAG> later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x4]
--> $DIR/aliasing_mut2.rs:LL:CC
|
LL | let _v = *x;
| ^^
= help: this transition corresponds to a loss of write permissions
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC
note: inside `main`

View File

@ -5,18 +5,18 @@ LL | *x = 1;
| ^^^^^^ write access through <TAG> is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> has state Frozen which forbids this child write access
= help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> $DIR/aliasing_mut3.rs:LL:CC
|
LL | pub fn safe(x: &mut i32, y: &i32) {
| ^
help: the accessed tag <TAG> later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
help: the accessed tag <TAG> later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
--> $DIR/aliasing_mut3.rs:LL:CC
|
LL | pub fn safe(x: &mut i32, y: &i32) {
| ^
= help: this transition corresponds to a loss of write permissions
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC
note: inside `main`

View File

@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
= help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled
= help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Reserved (conflicted)) to become Disabled
= help: protected tags must never be Disabled
help: the accessed tag <TAG> was created here
--> $DIR/newtype_pair_retagging.rs:LL:CC
@ -18,12 +18,12 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
|
LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
| ^^
help: the protected tag <TAG> later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
help: the protected tag <TAG> later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
--> $DIR/newtype_pair_retagging.rs:LL:CC
|
LL | || drop(Box::from_raw(ptr)),
| ^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to a loss of write permissions
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC

View File

@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
= help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled
= help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Reserved (conflicted)) to become Disabled
= help: protected tags must never be Disabled
help: the accessed tag <TAG> was created here
--> $DIR/newtype_retagging.rs:LL:CC
@ -18,12 +18,12 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
|
LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
| ^^
help: the protected tag <TAG> later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
help: the protected tag <TAG> later transitioned to Reserved (conflicted) due to a reborrow (acting as a foreign read access) at offsets [0x0..0x4]
--> $DIR/newtype_retagging.rs:LL:CC
|
LL | || drop(Box::from_raw(ptr)),
| ^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to a loss of write permissions
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC

View File

@ -1,29 +0,0 @@
//@revisions: stack tree
//@compile-flags: -Zmiri-preemption-rate=0
//@[tree]compile-flags: -Zmiri-tree-borrows
use std::thread;
#[derive(Copy, Clone)]
struct SendPtr(*mut i32);
unsafe impl Send for SendPtr {}
fn main() {
let mut mem = 0;
let ptr = SendPtr(&mut mem as *mut _);
let t = thread::spawn(move || {
let ptr = ptr;
// We do a protected 2phase retag (but no write!) in this thread.
fn retag(_x: &mut i32) {} //~[tree]ERROR: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>`
retag(unsafe { &mut *ptr.0 }); //~[stack]ERROR: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>`
});
// We do a read in the main thread.
unsafe { ptr.0.read() };
// These two operations do not commute -- if the read happens after the retag, the retagged pointer
// gets frozen! So we want this to be considered UB so that we can still freely move the read around
// in this thread without worrying about reordering with retags in other threads.
t.join().unwrap();
}

View File

@ -1,25 +0,0 @@
error: Undefined Behavior: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here
--> $DIR/retag_data_race_protected_read.rs:LL:CC
|
LL | fn retag(_x: &mut i32) {}
| ^^ Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here
|
help: and (1) occurred earlier here
--> $DIR/retag_data_race_protected_read.rs:LL:CC
|
LL | unsafe { ptr.0.read() };
| ^^^^^^^^^^^^
= 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 (of the first span):
= note: inside `main::{closure#0}::retag` at $DIR/retag_data_race_protected_read.rs:LL:CC
note: inside closure
--> $DIR/retag_data_race_protected_read.rs:LL:CC
|
LL | ... retag(unsafe { &mut *ptr.0 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -19,11 +19,17 @@ LL | | let non_copy = S(42);
LL | |
LL | | }
| |_____^
help: the protected tag <TAG> was created here, in the initial state Active
help: the protected tag <TAG> was created here, in the initial state Reserved
--> $DIR/arg_inplace_mutate.rs:LL:CC
|
LL | unsafe { ptr.write(S(0)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
--> $DIR/arg_inplace_mutate.rs:LL:CC
|
LL | unsafe { ptr.write(S(0)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: BACKTRACE (of the first span):
= note: inside `callee` at $DIR/arg_inplace_mutate.rs:LL:CC
note: inside `main`

View File

@ -19,11 +19,17 @@ LL | | let non_copy = S(42);
LL | |
LL | | }
| |_____^
help: the protected tag <TAG> was created here, in the initial state Active
help: the protected tag <TAG> was created here, in the initial state Reserved
--> $DIR/arg_inplace_observe_during.rs:LL:CC
|
LL | x.0 = 0;
| ^^^^^^^
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
--> $DIR/arg_inplace_observe_during.rs:LL:CC
|
LL | x.0 = 0;
| ^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: BACKTRACE (of the first span):
= note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC
note: inside `main`

View File

@ -19,11 +19,17 @@ LL | | let ptr = &raw mut x;
LL | | }
LL | | }
| |_____^
help: the protected tag <TAG> was created here, in the initial state Active
help: the protected tag <TAG> was created here, in the initial state Reserved
--> $DIR/return_pointer_aliasing.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^^^^^^^^^^^^
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
--> $DIR/return_pointer_aliasing.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: BACKTRACE (of the first span):
= note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC
note: inside `main`

View File

@ -19,11 +19,17 @@ LL | | let ptr = &raw mut _x;
LL | | }
LL | | }
| |_____^
help: the protected tag <TAG> was created here, in the initial state Active
help: the protected tag <TAG> was created here, in the initial state Reserved
--> $DIR/return_pointer_aliasing2.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
--> $DIR/return_pointer_aliasing2.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: BACKTRACE (of the first span):
= note: inside `myfun` at $DIR/return_pointer_aliasing2.rs:LL:CC
note: inside `main`

View File

@ -0,0 +1,30 @@
//@only-target-x86_64
#![allow(improper_ctypes_definitions)]
use std::arch::x86_64::*;
use std::mem::transmute;
#[no_mangle]
#[target_feature(enable = "avx")]
pub unsafe extern "C" fn foo(_y: f32, x: __m256) -> __m256 {
x
}
pub fn bar(x: __m256) -> __m256 {
// The first and second argument get mixed up here since caller
// and callee do not have the same feature flags.
// In Miri, we don't have a concept of "dynamically available feature flags",
// so this will always lead to an error due to calling a function that requires
// an unavailable feature. If we ever support dynamically available features,
// this will need some dedicated checks.
unsafe { foo(0.0, x) } //~ERROR: unavailable target features
}
fn assert_eq_m256(a: __m256, b: __m256) {
unsafe { assert_eq!(transmute::<_, [f32; 8]>(a), transmute::<_, [f32; 8]>(b)) }
}
fn main() {
let input = unsafe { transmute::<_, __m256>([1.0f32; 8]) };
let copy = bar(input);
assert_eq_m256(input, copy);
}

View File

@ -0,0 +1,20 @@
error: Undefined Behavior: calling a function that requires unavailable target features: avx
--> $DIR/simd_feature_flag_difference.rs:LL:CC
|
LL | unsafe { foo(0.0, x) }
| ^^^^^^^^^^^ calling a function that requires unavailable target features: avx
|
= 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 `bar` at $DIR/simd_feature_flag_difference.rs:LL:CC
note: inside `main`
--> $DIR/simd_feature_flag_difference.rs:LL:CC
|
LL | let copy = bar(input);
| ^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -0,0 +1,30 @@
//@compile-flags: -Zmiri-preemption-rate=0
use std::thread;
#[derive(Copy, Clone)]
struct SendPtr(*mut i32);
unsafe impl Send for SendPtr {}
fn main() {
let mut mem = 0;
let ptr = SendPtr(&mut mem as *mut _);
let t = thread::spawn(move || {
let ptr = ptr;
// We do a protected mutable retag (but no write!) in this thread.
fn retag(_x: &mut i32) {}
retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>`
});
// We do a read in the main thread.
unsafe { ptr.0.read() };
// These two operations do not commute!
// - In Stacked Borrows, if the read happens after the retag it will `Disable` the pointer.
// - In Tree Borrows, if the read happens after the retag, the retagged pointer gets frozen!
// Ideally we would want this to be considered UB so that we can still freely move the read around
// in this thread without worrying about reordering with retags in other threads,
// but in Tree Borrows we have found worse issues that occur if we make this a data race.
t.join().unwrap();
}

View File

@ -1,12 +1,12 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Re*| └─┬──<TAG=base>
| Re*| ├─┬──<TAG=x>
| Re*| │ └─┬──<TAG=caller:x>
| Re*| │ └────<TAG=callee:x> Strongly protected
| Re*| └────<TAG=y, callee:y, caller:y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| RsM | └─┬──<TAG=base>
| RsM | ├─┬──<TAG=x>
| RsM | │ └─┬──<TAG=caller:x>
| RsM | │ └────<TAG=callee:x> Strongly protected
| RsM | └────<TAG=y, callee:y, caller:y>
──────────────────────────────────────────────────
error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) is forbidden
--> $DIR/cell-protected-write.rs:LL:CC

View File

@ -1,12 +1,12 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=n>
| Res| ├─┬──<TAG=x>
| Res| │ └─┬──<TAG=caller:x>
| Res| │ └────<TAG=callee:x> Strongly protected
| Res| └────<TAG=y, callee:y, caller:y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=n>
| Rs | ├─┬──<TAG=x>
| Rs | │ └─┬──<TAG=caller:x>
| Rs | │ └────<TAG=callee:x> Strongly protected
| Rs | └────<TAG=y, callee:y, caller:y>
──────────────────────────────────────────────────
error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) is forbidden
--> $DIR/int-protected-write.rs:LL:CC

View File

@ -0,0 +1,117 @@
// We ensure a deterministic execution.
// Note that we are *also* using barriers: the barriers enforce the
// specific interleaving of operations that we want, but only the preemption
// rate guarantees that the error message is also deterministic.
//@compile-flags: -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-tree-borrows
use std::sync::{Arc, Barrier};
use std::thread;
// A way to send raw pointers across threads.
// Note that when using this in closures will require explicit copying
// `let ptr = ptr;` to force the borrow checker to copy the `Send` wrapper
// instead of just copying the inner `!Send` field.
#[derive(Copy, Clone)]
struct SendPtr(*mut u8);
unsafe impl Send for SendPtr {}
fn main() {
retagx_retagy_retx_writey_rety();
}
// We're going to enforce a specific interleaving of two
// threads, we use this macro in an effort to make it feasible
// to check in the output that the execution is properly synchronized.
//
// Provide `synchronized!(thread, msg)` where thread is
// a `(thread_id: usize, barrier: Arc<Barrier>)`, and `msg` the message
// to be displayed when the thread reaches this point in the execution.
macro_rules! synchronized {
($thread:expr, $msg:expr) => {{
let (thread_id, barrier) = &$thread;
eprintln!("Thread {} executing: {}", thread_id, $msg);
barrier.wait();
}};
}
// Interleaving:
// retag x (protect)
// retag y (protect)
// spurious read x (target only, which we are *not* executing)
// ret x
// write y
// ret y
//
// This is an interleaving that will never *not* have UB in the target
// (`noalias` violation on `y`).
// For the spurious read to be allowed, we need to ensure there *is* UB
// in the source (i.e., without the spurious read).
//
// The interleaving differs from the one in `tests/pass/tree_borrows/spurious_read.rs` only
// in that it has the `write y` while `y` is still protected.
// When the write occurs after protection ends, both source and target are fine
// (checked by the `pass` test); when the write occurs during protection, both source
// and target are UB (checked by this test).
fn retagx_retagy_retx_writey_rety() {
let mut data = 0u8;
let ptr = SendPtr(std::ptr::addr_of_mut!(data));
let barrier = Arc::new(Barrier::new(2));
let bx = Arc::clone(&barrier);
let by = Arc::clone(&barrier);
// This thread only needs to
// - retag `x` protected
// - do a read through `x`
// - remove `x`'s protector
// Most of the complexity here is synchronization.
let thread_x = thread::spawn(move || {
let b = (1, bx);
synchronized!(b, "start");
let ptr = ptr;
synchronized!(b, "retag x (&mut, protect)");
fn as_mut(x: &mut u8, b: (usize, Arc<Barrier>)) -> *mut u8 {
synchronized!(b, "retag y (&mut, protect)");
synchronized!(b, "location where spurious read of x would happen in the target");
// This is ensuring taht we have UB *without* the spurious read,
// so we don't read here.
synchronized!(b, "ret x");
synchronized!(b, "write y");
let x = x as *mut u8;
x
}
let _x = as_mut(unsafe { &mut *ptr.0 }, b.clone());
synchronized!(b, "ret y");
synchronized!(b, "end");
});
// This thread's job is to
// - retag `y` protected
// - (wait for the other thread to return so that there is no foreign protector when we write)
// - attempt a write through `y`.
// - (UB should have occured by now, but the next step would be to
// remove `y`'s protector)
let thread_y = thread::spawn(move || {
let b = (2, by);
synchronized!(b, "start");
let ptr = ptr;
synchronized!(b, "retag x (&mut, protect)");
synchronized!(b, "retag y (&mut, protect)");
fn as_mut(y: &mut u8, b: (usize, Arc<Barrier>)) -> *mut u8 {
synchronized!(b, "location where spurious read of x would happen in the target");
synchronized!(b, "ret x");
let y = y as *mut u8;
synchronized!(b, "write y");
unsafe {
*y = 2; //~ERROR: /write access through .* is forbidden/
}
synchronized!(b, "ret y");
y
}
let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone());
synchronized!(b, "end");
});
thread_x.join().unwrap();
thread_y.join().unwrap();
}

View File

@ -0,0 +1,44 @@
Thread 1 executing: start
Thread 2 executing: start
Thread 2 executing: retag x (&mut, protect)
Thread 1 executing: retag x (&mut, protect)
Thread 1 executing: retag y (&mut, protect)
Thread 2 executing: retag y (&mut, protect)
Thread 2 executing: location where spurious read of x would happen in the target
Thread 1 executing: location where spurious read of x would happen in the target
Thread 1 executing: ret x
Thread 2 executing: ret x
Thread 2 executing: write y
Thread 1 executing: write y
Thread 1 executing: ret y
error: Undefined Behavior: write access through <TAG> is forbidden
--> $DIR/spurious_read.rs:LL:CC
|
LL | *y = 2;
| ^^^^^^ write access through <TAG> is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> $DIR/spurious_read.rs:LL:CC
|
LL | fn as_mut(y: &mut u8, b: (usize, Arc<Barrier>)) -> *mut u8 {
| ^
help: the accessed tag <TAG> later transitioned to Reserved (conflicted) due to a protector release (acting as a foreign read access) on every location previously accessed by this tag
--> $DIR/spurious_read.rs:LL:CC
|
LL | }
| ^
= help: this transition corresponds to a temporary loss of write permissions until function exit
= note: BACKTRACE (of the first span):
= note: inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` at $DIR/spurious_read.rs:LL:CC
note: inside closure
--> $DIR/spurious_read.rs:LL:CC
|
LL | let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -3,6 +3,7 @@
#![feature(io_error_more)]
use std::fs::{remove_file, File};
use std::mem::transmute;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
@ -375,6 +376,18 @@ fn test_sigrt() {
assert!(max - min >= 8)
}
fn test_dlsym() {
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) };
assert!(addr as usize == 0);
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) };
assert!(addr as usize != 0);
let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) };
assert_eq!(isatty(999), 0);
let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
assert_eq!(errno, libc::EBADF);
}
fn main() {
test_posix_gettimeofday();
test_posix_mkstemp();
@ -387,6 +400,7 @@ fn main() {
test_isatty();
test_clocks();
test_dlsym();
test_memcpy();
test_strcpy();

View File

@ -1,12 +1,12 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Re*| └────<TAG=data, x, y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| RsM | └────<TAG=data, x, y>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └────<TAG=data, x, y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └────<TAG=data, x, y>
──────────────────────────────────────────────────

View File

@ -1,36 +1,36 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=data>
| Res| └────<TAG=x>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=data>
| Rs | └────<TAG=x>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=data>
| Res| └─┬──<TAG=x>
| Res| └─┬──<TAG=caller:x>
| Res| └────<TAG=callee:x> Strongly protected
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=data>
| Rs | └─┬──<TAG=x>
| Rs | └─┬──<TAG=caller:x>
| Rs | └────<TAG=callee:x> Strongly protected
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=data>
| Res| ├─┬──<TAG=x>
| Res| │ └─┬──<TAG=caller:x>
| Res| │ └────<TAG=callee:x>
| Res| └────<TAG=y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=data>
| Rs | ├─┬──<TAG=x>
| Rs | │ └─┬──<TAG=caller:x>
| Rs | │ └────<TAG=callee:x>
| Rs | └────<TAG=y>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=data>
| Dis| ├─┬──<TAG=x>
| Dis| │ └─┬──<TAG=caller:x>
| Dis| │ └────<TAG=callee:x>
| Act| └────<TAG=y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=data>
| Dis | ├─┬──<TAG=x>
| Dis | │ └─┬──<TAG=caller:x>
| Dis | │ └────<TAG=callee:x>
| Act | └────<TAG=y>
──────────────────────────────────────────────────

View File

@ -1,31 +1,31 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1.. 2.. 10.. 11..100..101..1000..1001..1024
| Act| Act| Act| Act| Act| Act| Act| Act| Act| └─┬──<TAG=root of the allocation>
| Res| Act| Res| Act| Res| Act| Res| Act| Res| └─┬──<TAG=data, data>
|----| Act|----|?Dis|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[1]>
|----|----|----| Act|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[10]>
|----|----|----|----|----| Frz| ----| ?Dis| ----| ├────<TAG=data[100]>
|----|----|----|----|----|----| ----| Act| ----| └────<TAG=data[1000]>
0.. 1.. 2.. 10.. 11.. 100.. 101..1000..1001..1024
| Act | Act | Act | Act | Act | Act | Act | Act | Act | └─┬──<TAG=root of the allocation>
| Rs | Act | Rs | Act | Rs | Act | Rs | Act | Rs | └─┬──<TAG=data, data>
|-----| Act |-----|?Dis |-----|?Dis |-----|?Dis |-----| ├────<TAG=data[1]>
|-----|-----|-----| Act |-----|?Dis |-----|?Dis |-----| ├────<TAG=data[10]>
|-----|-----|-----|-----|-----| Frz |-----|?Dis |-----| ├────<TAG=data[100]>
|-----|-----|-----|-----|-----|-----|-----| Act |-----| └────<TAG=data[1000]>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Frz| └─┬──<TAG=x>
| Frz| ├─┬──<TAG=xa>
| Frz| │ ├────<TAG=xaa>
| Frz| │ └────<TAG=xab>
| Frz| ├─┬──<TAG=xb>
| Frz| │ └─┬──<TAG=xba>
| Frz| │ └─┬──<TAG=xbaa>
| Frz| │ └─┬──<TAG=xbaaa>
| Frz| │ └────<TAG=xbaaaa>
| Frz| └─┬──<TAG=xc>
| Frz| ├─┬──<TAG=xca>
| Frz| │ ├────<TAG=xcaa>
| Frz| │ └────<TAG=xcab>
| Frz| └─┬──<TAG=xcb>
| Frz| ├────<TAG=xcba>
| Frz| └────<TAG=xcbb>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Frz | └─┬──<TAG=x>
| Frz | ├─┬──<TAG=xa>
| Frz | │ ├────<TAG=xaa>
| Frz | │ └────<TAG=xab>
| Frz | ├─┬──<TAG=xb>
| Frz | │ └─┬──<TAG=xba>
| Frz | │ └─┬──<TAG=xbaa>
| Frz | │ └─┬──<TAG=xbaaa>
| Frz | │ └────<TAG=xbaaaa>
| Frz | └─┬──<TAG=xc>
| Frz | ├─┬──<TAG=xca>
| Frz | │ ├────<TAG=xcaa>
| Frz | │ └────<TAG=xcab>
| Frz | └─┬──<TAG=xcb>
| Frz | ├────<TAG=xcba>
| Frz | └────<TAG=xcbb>
──────────────────────────────────────────────────

View File

@ -0,0 +1,114 @@
//@compile-flags: -Zmiri-tree-borrows
// This test relies on a specific interleaving that cannot be enforced
// with just barriers. We must remove preemption so that the execution and the
// error messages are deterministic.
//@compile-flags: -Zmiri-preemption-rate=0
use std::ptr::addr_of_mut;
use std::sync::{Arc, Barrier};
use std::thread;
#[derive(Copy, Clone)]
struct SendPtr(*mut u8);
unsafe impl Send for SendPtr {}
// This test features the problematic pattern
//
// read x || retag y (&mut, protect)
// -- sync --
// || write y
//
// In which
// - one interleaving (`1:read; 2:retag; 2:write`) does not have UB if retags
// count only as reads for the data race model,
// - the other interleaving (`2:retag; 1:read; 2:write`) has UB (`noalias` violation).
//
// The interleaving executed here is the one that does not have UB,
// i.e.
// 1:read x
// 2:retag y
// 2:write y
//
// Tree Borrows considers that the read of `x` cannot be in conflict
// with `y` because `y` did not even exist yet when `x` was accessed.
//
// As long as we are not emitting any writes for the data race model
// upon retags of mutable references, it should not have any issue with
// this code either.
// We do not want to emit a write for the data race model, because
// although there is race-like behavior going on in this pattern
// (where some but not all interleavings contain UB), making this an actual
// data race has the confusing consequence of one single access being treated
// as being of different `AccessKind`s by different parts of Miri
// (a retag would be always a read for the aliasing model, and sometimes a write
// for the data race model).
// The other interleaving is a subsequence of `tests/fail/tree_borrows/spurious_read.rs`
// which asserts that
// 2:retag y
// 1:read x
// 2:write y
// is UB.
type IdxBarrier = (usize, Arc<Barrier>);
// We're going to enforce a specific interleaving of two
// threads, we use this macro in an effort to make it feasible
// to check in the output that the execution is properly synchronized.
//
// Provide `synchronized!(thread, msg)` where thread is
// a `(thread_id: usize, barrier: Arc<Barrier>)`, and `msg` the message
// to be displayed when the thread reaches this point in the execution.
macro_rules! synchronized {
($thread:expr, $msg:expr) => {{
let (thread_id, barrier) = &$thread;
eprintln!("Thread {} executing: {}", thread_id, $msg);
barrier.wait();
}};
}
fn thread_1(x: SendPtr, barrier: IdxBarrier) {
let x = unsafe { &mut *x.0 };
synchronized!(barrier, "spawn");
synchronized!(barrier, "read x || retag y");
// This is the interleaving without UB: by the time
// the other thread starts retagging, this thread
// has already finished all its work using `y`.
let _v = *x;
synchronized!(barrier, "write y");
synchronized!(barrier, "exit");
}
fn thread_2(y: SendPtr, barrier: IdxBarrier) {
let y = unsafe { &mut *y.0 };
synchronized!(barrier, "spawn");
fn write(y: &mut u8, v: u8, barrier: &IdxBarrier) {
synchronized!(barrier, "write y");
*y = v;
}
synchronized!(barrier, "read x || retag y");
// We don't use a barrier here so that *if* the retag counted as a write
// for the data race model, then it would be UB.
// We still want to make sure that the other thread goes first as per the
// interleaving that we are testing, so we use `yield_now + preemption-rate=0`
// which has the effect of forcing a specific interleaving while still
// not counting as "synchronization" from the point of view of the data
// race model.
thread::yield_now();
write(&mut *y, 42, &barrier);
synchronized!(barrier, "exit");
}
fn main() {
let mut data = 0u8;
let p = SendPtr(addr_of_mut!(data));
let barrier = Arc::new(Barrier::new(2));
let b1 = (1, Arc::clone(&barrier));
let b2 = (2, Arc::clone(&barrier));
let h1 = thread::spawn(move || thread_1(p, b1));
let h2 = thread::spawn(move || thread_2(p, b2));
h1.join().unwrap();
h2.join().unwrap();
}

View File

@ -0,0 +1,8 @@
Thread 1 executing: spawn
Thread 2 executing: spawn
Thread 2 executing: read x || retag y
Thread 1 executing: read x || retag y
Thread 1 executing: write y
Thread 2 executing: write y
Thread 2 executing: exit
Thread 1 executing: exit

View File

@ -1,15 +1,15 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=parent>
| Act| └────<TAG=x>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=parent>
| Act | └────<TAG=x>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=parent>
| Frz| ├────<TAG=x>
| Res| └────<TAG=y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=parent>
| Frz | ├────<TAG=x>
| Rs | └────<TAG=y>
──────────────────────────────────────────────────

View File

@ -1,58 +1,58 @@
[interior mut + protected] Foreign Read: Re* -> Frz
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Re*| └─┬──<TAG=base>
| Re*| ├─┬──<TAG=x>
| Re*| │ └─┬──<TAG=caller:x>
| Frz| │ └────<TAG=callee:x>
| Re*| └────<TAG=y, caller:y, callee:y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| RsM | └─┬──<TAG=base>
| RsM | ├─┬──<TAG=x>
| RsM | │ └─┬──<TAG=caller:x>
| RsCM| │ └────<TAG=callee:x>
| RsM | └────<TAG=y, caller:y, callee:y>
──────────────────────────────────────────────────
[interior mut] Foreign Read: Re* -> Re*
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 8
| Act| └─┬──<TAG=root of the allocation>
| Re*| └─┬──<TAG=base>
| Re*| ├────<TAG=x>
| Re*| └────<TAG=y>
0.. 8
| Act | └─┬──<TAG=root of the allocation>
| RsM | └─┬──<TAG=base>
| RsM | ├────<TAG=x>
| RsM | └────<TAG=y>
──────────────────────────────────────────────────
[interior mut] Foreign Write: Re* -> Re*
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 8
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Re*| ├────<TAG=x>
| Act| └────<TAG=y>
0.. 8
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| RsM | ├────<TAG=x>
| Act | └────<TAG=y>
──────────────────────────────────────────────────
[protected] Foreign Read: Res -> Frz
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=base>
| Res| ├─┬──<TAG=x>
| Res| │ └─┬──<TAG=caller:x>
| Frz| │ └────<TAG=callee:x>
| Res| └────<TAG=y, caller:y, callee:y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=base>
| Rs | ├─┬──<TAG=x>
| Rs | │ └─┬──<TAG=caller:x>
| RsC | │ └────<TAG=callee:x>
| Rs | └────<TAG=y, caller:y, callee:y>
──────────────────────────────────────────────────
[] Foreign Read: Res -> Res
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=base>
| Res| ├────<TAG=x>
| Res| └────<TAG=y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=base>
| Rs | ├────<TAG=x>
| Rs | └────<TAG=y>
──────────────────────────────────────────────────
[] Foreign Write: Res -> Dis
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Dis| ├────<TAG=x>
| Act| └────<TAG=y>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Dis | ├────<TAG=x>
| Act | └────<TAG=y>
──────────────────────────────────────────────────

View File

@ -0,0 +1,115 @@
// We ensure a deterministic execution.
// Note that we are *also* using barriers: the barriers enforce the
// specific interleaving of operations that we want, but only the preemption
// rate guarantees that the error message is also deterministic.
//@compile-flags: -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-tree-borrows
use std::sync::{Arc, Barrier};
use std::thread;
// A way to send raw pointers across threads.
// Note that when using this in closures will require explicit copying
// `let ptr = ptr;` to force the borrow checker to copy the `Send` wrapper
// instead of just copying the inner `!Send` field.
#[derive(Copy, Clone)]
struct SendPtr(*mut u8);
unsafe impl Send for SendPtr {}
fn main() {
retagx_retagy_spuriousx_retx_rety_writey();
}
// We're going to enforce a specific interleaving of two
// threads, we use this macro in an effort to make it feasible
// to check in the output that the execution is properly synchronized.
//
// Provide `synchronized!(thread, msg)` where thread is
// a `(thread_id: usize, barrier: Arc<Barrier>)`, and `msg` the message
// to be displayed when the thread reaches this point in the execution.
macro_rules! synchronized {
($thread:expr, $msg:expr) => {{
let (thread_id, barrier) = &$thread;
eprintln!("Thread {} executing: {}", thread_id, $msg);
barrier.wait();
}};
}
// Interleaving:
// retag x (protect)
// retag y (protect)
// spurious read x (target only, which we are executing)
// ret x
// ret y
// write y
//
// This is an interleaving that will never have UB in the source
// (`x` is never accessed for the entire time that `y` is protected).
// For the spurious read to be allowed, we need to check that there is
// no UB in the target (i.e., *with* the spurious read).
//
// The interleaving differs from the one in `tests/fail/tree_borrows/spurious_read.rs` only
// in that it has the `write y` while `y` is no longer protected.
// When the write occurs after protection ends, both source and target are fine
// (checked by this test); when the write occurs during protection, both source
// and target are UB (checked by the `fail` test).
fn retagx_retagy_spuriousx_retx_rety_writey() {
let mut data = 0u8;
let ptr = SendPtr(std::ptr::addr_of_mut!(data));
let barrier = Arc::new(Barrier::new(2));
let bx = Arc::clone(&barrier);
let by = Arc::clone(&barrier);
// This thread only needs to
// - retag `x` protected
// - do a read through `x`
// - remove `x`'s protector
// Most of the complexity here is synchronization.
let thread_x = thread::spawn(move || {
let b = (1, bx);
synchronized!(b, "start");
let ptr = ptr;
synchronized!(b, "retag x (&mut, protect)");
fn as_mut(x: &mut u8, b: (usize, Arc<Barrier>)) -> *mut u8 {
synchronized!(b, "retag y (&mut, protect)");
synchronized!(b, "spurious read x");
let _v = *x;
synchronized!(b, "ret x");
let x = x as *mut u8;
x
}
let _x = as_mut(unsafe { &mut *ptr.0 }, b.clone());
synchronized!(b, "ret y");
synchronized!(b, "write y");
synchronized!(b, "end");
});
// This thread's job is to
// - retag `y` protected
// - (wait a bit that the other thread performs its spurious read)
// - remove `y`'s protector
// - attempt a write through `y`.
let thread_y = thread::spawn(move || {
let b = (2, by);
synchronized!(b, "start");
let ptr = ptr;
synchronized!(b, "retag x (&mut, protect)");
synchronized!(b, "retag y (&mut, protect)");
fn as_mut(y: &mut u8, b: (usize, Arc<Barrier>)) -> *mut u8 {
synchronized!(b, "spurious read x");
synchronized!(b, "ret x");
let y = y as *mut u8;
y
}
let y = as_mut(unsafe { &mut *ptr.0 }, b.clone());
synchronized!(b, "ret y");
synchronized!(b, "write y");
unsafe {
*y = 2;
}
synchronized!(b, "end");
});
thread_x.join().unwrap();
thread_y.join().unwrap();
}

View File

@ -0,0 +1,16 @@
Thread 1 executing: start
Thread 2 executing: start
Thread 2 executing: retag x (&mut, protect)
Thread 1 executing: retag x (&mut, protect)
Thread 1 executing: retag y (&mut, protect)
Thread 2 executing: retag y (&mut, protect)
Thread 2 executing: spurious read x
Thread 1 executing: spurious read x
Thread 1 executing: ret x
Thread 2 executing: ret x
Thread 2 executing: ret y
Thread 1 executing: ret y
Thread 1 executing: write y
Thread 2 executing: write y
Thread 2 executing: end
Thread 1 executing: end

View File

@ -12,6 +12,7 @@ fn main() {
two_mut_protected_same_alloc();
direct_mut_to_const_raw();
local_addr_of_mut();
returned_mut_is_usable();
// Stacked Borrows tests
read_does_not_invalidate1();
@ -93,6 +94,24 @@ fn two_mut_protected_same_alloc() {
write_second(&mut data.0, &mut data.1);
}
// This checks that a reborrowed mutable reference returned from a function
// is actually writeable.
// The fact that this is not obvious is due to the addition of
// implicit reads on function exit that might freeze the return value.
fn returned_mut_is_usable() {
fn reborrow(x: &mut u8) -> &mut u8 {
let y = &mut *x;
// Activate the reference so that it is vulnerable to foreign reads.
*y = *y;
y
// An implicit read through `x` is inserted here.
}
let mut data = 0;
let x = &mut data;
let y = reborrow(x);
*y = 1;
}
// ----- The tests below were taken from Stacked Borrows ----
// Make sure that reading from an `&mut` does, like reborrowing to `&`,

View File

@ -1,21 +1,21 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=base>
| Res| └────<TAG=raw, uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=base>
| Rs | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Act| └────<TAG=raw, uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Act| └────<TAG=raw, uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────

View File

@ -1,24 +1,24 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Res| └─┬──<TAG=base>
| Res| └─┬──<TAG=raw>
|----| └────<TAG=uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Rs | └─┬──<TAG=base>
| Rs | └─┬──<TAG=raw>
|-----| └────<TAG=uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Act| └─┬──<TAG=raw>
| Act| └────<TAG=uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └─┬──<TAG=raw>
| Act | └────<TAG=uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act| └─┬──<TAG=root of the allocation>
| Act| └─┬──<TAG=base>
| Act| └─┬──<TAG=raw>
| Dis| └────<TAG=uniq, uniq>
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └─┬──<TAG=raw>
| Dis | └────<TAG=uniq, uniq>
──────────────────────────────────────────────────

View File

@ -1,6 +1,6 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 2
| Act| └─┬──<TAG=root of the allocation>
| Res| └────<TAG=base.as_ptr(), base.as_ptr(), raw_parts.0, reconstructed.as_ptr(), reconstructed.as_ptr()>
0.. 2
| Act | └─┬──<TAG=root of the allocation>
| Rs | └────<TAG=base.as_ptr(), base.as_ptr(), raw_parts.0, reconstructed.as_ptr(), reconstructed.as_ptr()>
──────────────────────────────────────────────────

View File

@ -1,8 +1,8 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 2
| Act| └─┬──<TAG=root of the allocation>
|----| └─┬──<TAG=base.as_ptr(), base.as_ptr()>
|----| └─┬──<TAG=raw_parts.0>
|----| └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
0.. 2
| Act | └─┬──<TAG=root of the allocation>
|-----| └─┬──<TAG=base.as_ptr(), base.as_ptr()>
|-----| └─┬──<TAG=raw_parts.0>
|-----| └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
──────────────────────────────────────────────────

View File

@ -47,6 +47,7 @@ const EXCEPTIONS: &[(&str, &str)] = &[
("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
("mdbook", "MPL-2.0"), // mdbook
("openssl", "Apache-2.0"), // opt-dist
("option-ext", "MPL-2.0"), // cargo-miri (via `directories`)
("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses)
("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
("self_cell", "Apache-2.0"), // rustc (fluent translations)