Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aa1c459

Browse files
committedApr 6, 2024·
Auto merge of #123557 - GuillaumeGomez:rollup-3af7urf, r=GuillaumeGomez
Rollup of 4 pull requests Successful merges: - #123541 (remove miri-test-libstd hacks that are no longer needed) - #123552 (Add missing -Zquery-dep-graph to the spike-neg incr comp tests) - #123553 (Miri subtree update) - #123554 (Simplify/cleanup `search-result-color.goml`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 773fb88 + 3a203b0 commit aa1c459

39 files changed

+1153
-1266
lines changed
 

‎library/alloc/src/lib.rs

-6
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@
5656
//! [`Rc`]: rc
5757
//! [`RefCell`]: core::cell
5858
59-
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
60-
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
61-
// rustc itself never sets the feature, so this line has no effect there.
62-
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
63-
//
6459
#![allow(unused_attributes)]
6560
#![stable(feature = "alloc", since = "1.36.0")]
6661
#![doc(
@@ -71,7 +66,6 @@
7166
#![doc(cfg_hide(
7267
not(test),
7368
not(any(test, bootstrap)),
74-
any(not(feature = "miri-test-libstd"), test, doctest),
7569
no_global_oom_handling,
7670
not(no_global_oom_handling),
7771
not(no_rc),

‎library/core/src/lib.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,7 @@
5757
//
5858
// This cfg won't affect doc tests.
5959
#![cfg(not(test))]
60-
// To run core tests without x.py without ending up with two copies of core, Miri needs to be
61-
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
62-
// rustc itself never sets the feature, so this line has no effect there.
63-
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
60+
//
6461
#![stable(feature = "core", since = "1.6.0")]
6562
#![doc(
6663
html_playground_url = "https://play.rust-lang.org/",
@@ -71,7 +68,6 @@
7168
#![doc(rust_logo)]
7269
#![doc(cfg_hide(
7370
not(test),
74-
any(not(feature = "miri-test-libstd"), test, doctest),
7571
no_fp_fmt_parse,
7672
target_pointer_width = "16",
7773
target_pointer_width = "32",

‎library/std/src/lib.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,7 @@
212212
//! [rust-discord]: https://discord.gg/rust-lang
213213
//! [array]: prim@array
214214
//! [slice]: prim@slice
215-
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
216-
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
217-
// rustc itself never sets the feature, so this line has no effect there.
218-
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
219-
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
220-
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
221-
//
215+
222216
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
223217
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
224218
#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)]

‎src/tools/miri/.github/workflows/ci.yml

+17-11
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ jobs:
2424
include:
2525
- os: ubuntu-latest
2626
host_target: x86_64-unknown-linux-gnu
27-
- os: macos-latest
28-
host_target: x86_64-apple-darwin
27+
- os: macos-14
28+
host_target: aarch64-apple-darwin
2929
- os: windows-latest
3030
host_target: i686-pc-windows-msvc
3131
runs-on: ${{ matrix.os }}
@@ -49,15 +49,16 @@ jobs:
4949
with:
5050
path: |
5151
# Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
52-
~/.cargo/bin
52+
# Cache package/registry information
5353
~/.cargo/registry/index
5454
~/.cargo/registry/cache
5555
~/.cargo/git/db
56-
# contains package information of crates installed via `cargo install`.
56+
# Cache installed binaries
57+
~/.cargo/bin
5758
~/.cargo/.crates.toml
5859
~/.cargo/.crates2.json
59-
key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }}
60-
restore-keys: ${{ runner.os }}-cargo-reset20230315
60+
key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }}
61+
restore-keys: cargo-${{ runner.os }}-reset20240331
6162

6263
- name: Install rustup-toolchain-install-master
6364
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
@@ -98,15 +99,16 @@ jobs:
9899
with:
99100
path: |
100101
# Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
101-
~/.cargo/bin
102+
# Cache package/registry information
102103
~/.cargo/registry/index
103104
~/.cargo/registry/cache
104105
~/.cargo/git/db
105-
# contains package information of crates installed via `cargo install`.
106+
# Cache installed binaries
107+
~/.cargo/bin
106108
~/.cargo/.crates.toml
107109
~/.cargo/.crates2.json
108-
key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }}
109-
restore-keys: ${{ runner.os }}-cargo-reset20230315
110+
key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }}
111+
restore-keys: cargo-${{ runner.os }}-reset20240331
110112

111113
- name: Install rustup-toolchain-install-master
112114
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
@@ -130,6 +132,10 @@ jobs:
130132
run: ./miri fmt --check
131133
- name: clippy
132134
run: ./miri clippy -- -D warnings
135+
- name: clippy (no features)
136+
run: ./miri clippy --no-default-features -- -D warnings
137+
- name: clippy (all features)
138+
run: ./miri clippy --all-features -- -D warnings
133139
- name: rustdoc
134140
run: RUSTDOCFLAGS="-Dwarnings" ./miri cargo doc --document-private-items
135141

@@ -189,7 +195,7 @@ jobs:
189195
with:
190196
fetch-depth: 256 # get a bit more of the history
191197
- name: install josh-proxy
192-
run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
198+
run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
193199
- name: setup bot git name and email
194200
run: |
195201
git config --global user.name 'The Miri Cronjob Bot'

‎src/tools/miri/CONTRIBUTING.md

+7-11
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,20 @@ We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit chan
241241
rustc and Miri repositories. You can install it as follows:
242242

243243
```sh
244-
cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
244+
RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
245245
```
246246

247247
Josh will automatically be started and stopped by `./miri`.
248248

249249
### Importing changes from the rustc repo
250250

251+
*Note: this usually happens automatically, so these steps rarely have to be done by hand.*
252+
251253
We assume we start on an up-to-date master branch in the Miri repo.
252254

253255
```sh
254256
# Fetch and merge rustc side of the history. Takes ca 5 min the first time.
255-
# This will also update the 'rustc-version' file.
257+
# This will also update the `rustc-version` file.
256258
./miri rustc-pull
257259
# Update local toolchain and apply formatting.
258260
./miri toolchain && ./miri fmt
@@ -266,12 +268,6 @@ needed.
266268

267269
### Exporting changes to the rustc repo
268270

269-
Keep in mind that pushing is the most complicated job that josh has to do -- pulling just filters
270-
the rustc history, but pushing needs to construct a new rustc history that would filter to the given
271-
Miri history! To avoid problems, it is a good idea to always pull immediately before you push. If
272-
you are getting strange errors, chances are you are running into [this josh
273-
bug](https://github.com/josh-project/josh/issues/998). In that case, please get in touch on Zulip.
274-
275271
We will use the josh proxy to push to your fork of rustc. Run the following in the Miri repo,
276272
assuming we are on an up-to-date master branch:
277273

@@ -280,9 +276,9 @@ assuming we are on an up-to-date master branch:
280276
./miri rustc-push YOUR_NAME miri
281277
```
282278

283-
This will create a new branch called 'miri' in your fork, and the output should
284-
include a link to create a rustc PR that will integrate those changes into the
285-
main repository.
279+
This will create a new branch called `miri` in your fork, and the output should include a link that
280+
creates a rustc PR to integrate those changes into the main repository. If that PR has conflicts,
281+
you need to pull rustc changes into Miri first, and then re-do the rustc push.
286282

287283
If this fails due to authentication problems, it can help to make josh push via ssh instead of
288284
https. Add the following to your `.gitconfig`:

‎src/tools/miri/ci/ci.sh

+57-45
Original file line numberDiff line numberDiff line change
@@ -27,60 +27,59 @@ export RUSTFLAGS="-D warnings"
2727
export CARGO_INCREMENTAL=0
2828
export CARGO_EXTRA_FLAGS="--locked"
2929

30-
# Determine configuration for installed build
30+
# Determine configuration for installed build (used by test-cargo-miri).
3131
echo "Installing release version of Miri"
32-
./miri install
33-
34-
echo "Checking various feature flag configurations"
35-
./miri check --no-default-features # make sure this can be built
36-
./miri check # and this, too
37-
# `--all-features` is used for the build below, so no extra check needed.
32+
time ./miri install
3833

3934
# Prepare debug build for direct `./miri` invocations.
4035
# We enable all features to make sure the Stacked Borrows consistency check runs.
4136
echo "Building debug version of Miri"
4237
export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features"
43-
./miri build --all-targets # the build that all the `./miri test` below will use
38+
time ./miri build --all-targets # the build that all the `./miri test` below will use
4439

4540
endgroup
4641

47-
# Test
42+
# Run tests. Recognizes these variables:
43+
# - MIRI_TEST_TARGET: the target to test. Empty for host target.
44+
# - GC_STRESS: if non-empty, run the GC stress test for the main test suite.
45+
# - MIR_OPT: if non-empty, re-run test `pass` tests with mir-opt-level=4
46+
# - MANY_SEEDS: if set to N, run the "many-seeds" tests N times
47+
# - TEST_BENCH: if non-empty, check that the benchmarks all build
48+
# - CARGO_MIRI_ENV: if non-empty, set some env vars and config to potentially confuse cargo-miri
4849
function run_tests {
49-
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
50+
if [ -n "${MIRI_TEST_TARGET-}" ]; then
5051
begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
5152
else
5253
begingroup "Testing host architecture"
5354
fi
5455

5556
## ui test suite
56-
# On the host, also stress-test the GC.
57-
if [ -z "${MIRI_TEST_TARGET:-}" ]; then
58-
MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
57+
if [ -n "${GC_STRESS-}" ]; then
58+
time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test
5959
else
60-
./miri test
60+
time ./miri test
6161
fi
6262

63-
# Host-only tests
64-
if [ -z "${MIRI_TEST_TARGET:-}" ]; then
65-
# Running these on all targets is unlikely to catch more problems and would
66-
# cost a lot of CI time.
67-
63+
## advanced tests
64+
if [ -n "${MIR_OPT-}" ]; then
6865
# Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the
6966
# way, too).
7067
# Optimizations change diagnostics (mostly backtraces), so we don't check
7168
# them. Also error locations change so we don't run the failing tests.
7269
# We explicitly enable debug-assertions here, they are disabled by -O but we have tests
7370
# which exist to check that we panic on debug assertion failures.
74-
MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic}
75-
71+
time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic}
72+
fi
73+
if [ -n "${MANY_SEEDS-}" ]; then
7674
# Also run some many-seeds tests. 64 seeds means this takes around a minute per test.
7775
# (Need to invoke via explicit `bash -c` for Windows.)
78-
for FILE in tests/many-seeds/*.rs; do
79-
MIRI_SEEDS=64 ./miri many-seeds "$BASH" -c "./miri run '$FILE'"
76+
time for FILE in tests/many-seeds/*.rs; do
77+
MIRI_SEEDS=$MANY_SEEDS ./miri many-seeds "$BASH" -c "./miri run '$FILE'"
8078
done
81-
79+
fi
80+
if [ -n "${TEST_BENCH-}" ]; then
8281
# Check that the benchmarks build and run, but without actually benchmarking.
83-
HYPERFINE="'$BASH' -c" ./miri bench
82+
time HYPERFINE="'$BASH' -c" ./miri bench
8483
fi
8584

8685
## test-cargo-miri
@@ -91,16 +90,18 @@ function run_tests {
9190
PYTHON=python
9291
fi
9392
# Some environment setup that attempts to confuse the heck out of cargo-miri.
94-
if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
95-
# These act up on Windows (`which miri` produces a filename that does not exist?!?),
96-
# so let's do this only on Linux. Also makes sure things work without these set.
97-
export RUSTC=$(which rustc) # Produces a warning unless we also set MIRI
93+
if [ -n "${CARGO_MIRI_ENV-}" ]; then
94+
# These act up on Windows (`which miri` produces a filename that does not exist?!?).
95+
# RUSTC is the main thing to set (it changes the first argument our wrapper will see).
96+
# Unless MIRI is also set, that produces a warning.
97+
export RUSTC=$(which rustc)
9898
export MIRI=$(rustc +miri --print sysroot)/bin/miri
99+
# We entirely ignore other wrappers.
100+
mkdir -p .cargo
101+
echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
99102
fi
100-
mkdir -p .cargo
101-
echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
102103
# Run the actual test
103-
${PYTHON} test-cargo-miri/run-test.py
104+
time ${PYTHON} test-cargo-miri/run-test.py
104105
# Clean up
105106
unset RUSTC MIRI
106107
rm -rf .cargo
@@ -109,7 +110,7 @@ function run_tests {
109110
}
110111

111112
function run_tests_minimal {
112-
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
113+
if [ -n "${MIRI_TEST_TARGET-}" ]; then
113114
begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
114115
else
115116
echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
@@ -126,38 +127,49 @@ function run_tests_minimal {
126127

127128
## Main Testing Logic ##
128129

129-
# Host target.
130-
run_tests
131-
132-
# Extra targets.
133130
# In particular, fully cover all tier 1 targets.
134131
case $HOST_TARGET in
135132
x86_64-unknown-linux-gnu)
133+
# Host
134+
GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
135+
# Extra tier 1
136136
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
137137
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
138-
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
138+
MIRI_TEST_TARGET=x86_64-apple-darwin run_tests
139139
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
140140
MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
141+
# Extra tier 2
142+
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
141143
MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
142-
# Some targets are only partially supported.
144+
# Partially supported targets (tier 2)
143145
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus
144146
MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus
145-
146147
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
147148
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
148149
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
149-
MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # no_std embedded architecture
150-
MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
150+
MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
151+
# Custom target JSON file
152+
MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std
151153
;;
152-
x86_64-apple-darwin)
154+
aarch64-apple-darwin)
155+
# Host (tier 2)
156+
GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
157+
# Extra tier 1
158+
MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
159+
# Extra tier 2
153160
MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture
154-
MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
155161
;;
156162
i686-pc-windows-msvc)
163+
# Host
164+
# Only smoke-test `many-seeds`; 64 runs take 15min here!
165+
GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests
166+
# Extra tier 1
167+
# We really want to ensure a Linux target works on a Windows host,
168+
# and a 64bit target works on a 32bit host.
157169
MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
158170
;;
159171
*)
160-
echo "FATAL: unknown OS"
172+
echo "FATAL: unknown host target: $HOST_TARGET"
161173
exit 1
162174
;;
163175
esac

‎src/tools/miri/miri-script/src/commands.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl Command {
297297
};
298298
// Prepare the branch. Pushing works much better if we use as base exactly
299299
// the commit that we pulled from last time, so we use the `rust-version`
300-
// file as a good approximation of that.
300+
// file to find out which commit that would be.
301301
println!("Preparing {github_user}/rust (base: {base})...");
302302
if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}")
303303
.ignore_stderr()

‎src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5baf1e13f568b61e121953bf6a3d09faee7dd446
1+
23d47dba319331d4418827cfbb8c1af283497d3c

‎src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl AccessCause {
4848
/// Complete data for an event:
4949
#[derive(Clone, Debug)]
5050
pub struct Event {
51-
/// Transformation of permissions that occured because of this event.
51+
/// Transformation of permissions that occurred because of this event.
5252
pub transition: PermTransition,
5353
/// Kind of the access that triggered this event.
5454
pub access_cause: AccessCause,
@@ -58,7 +58,7 @@ pub struct Event {
5858
/// `None` means that this is an implicit access to the entire allocation
5959
/// (used for the implicit read on protector release).
6060
pub access_range: Option<AllocRange>,
61-
/// The transition recorded by this event only occured on a subrange of
61+
/// The transition recorded by this event only occurred on a subrange of
6262
/// `access_range`: a single access on `access_range` triggers several events,
6363
/// each with their own mutually disjoint `transition_range`. No-op transitions
6464
/// should not be recorded as events, so the union of all `transition_range` is not

‎src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ impl Tree {
473473
let rperms = {
474474
let mut perms = UniValMap::default();
475475
// We manually set it to `Active` on all in-bounds positions.
476-
// We also ensure that it is initalized, so that no `Active` but
476+
// We also ensure that it is initialized, so that no `Active` but
477477
// not yet initialized nodes exist. Essentially, we pretend there
478478
// was a write that initialized these to `Active`.
479479
perms.insert(root_idx, LocationState::new_init(Permission::new_active()));

‎src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn protected_enforces_noalias() {
7575
}
7676
}
7777

78-
/// We are going to exhaustively test the possibily of inserting
78+
/// We are going to exhaustively test the possibility of inserting
7979
/// a spurious read in some code.
8080
///
8181
/// We choose some pointer `x` through which we want a spurious read to be inserted.
@@ -270,7 +270,7 @@ mod spurious_read {
270270
match self {
271271
TestEvent::Access(acc) => write!(f, "{acc}"),
272272
// The fields of the `Ret` variants just serve to make them
273-
// impossible to instanciate via the `RetX = NoRet` type; we can
273+
// impossible to instantiate via the `RetX = NoRet` type; we can
274274
// always ignore their value.
275275
TestEvent::RetX(_) => write!(f, "ret x"),
276276
TestEvent::RetY(_) => write!(f, "ret y"),
@@ -395,7 +395,7 @@ mod spurious_read {
395395
match evt {
396396
TestEvent::Access(acc) => self.perform_test_access(acc),
397397
// The fields of the `Ret` variants just serve to make them
398-
// impossible to instanciate via the `RetX = NoRet` type; we can
398+
// impossible to instantiate via the `RetX = NoRet` type; we can
399399
// always ignore their value.
400400
TestEvent::RetX(_) => self.end_protector_x(),
401401
TestEvent::RetY(_) => self.end_protector_y(),

‎src/tools/miri/src/machine.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc_target::spec::abi::Abi;
3131

3232
use crate::{
3333
concurrency::{data_race, weak_memory},
34-
shims::unix::FileHandler,
34+
shims::unix::FdTable,
3535
*,
3636
};
3737

@@ -463,9 +463,9 @@ pub struct MiriMachine<'mir, 'tcx> {
463463
pub(crate) validate: bool,
464464

465465
/// The table of file descriptors.
466-
pub(crate) file_handler: shims::unix::FileHandler,
466+
pub(crate) fds: shims::unix::FdTable,
467467
/// The table of directory descriptors.
468-
pub(crate) dir_handler: shims::unix::DirHandler,
468+
pub(crate) dirs: shims::unix::DirTable,
469469

470470
/// This machine's monotone clock.
471471
pub(crate) clock: Clock,
@@ -640,8 +640,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
640640
tls: TlsData::default(),
641641
isolated_op: config.isolated_op,
642642
validate: config.validate,
643-
file_handler: FileHandler::new(config.mute_stdout_stderr),
644-
dir_handler: Default::default(),
643+
fds: FdTable::new(config.mute_stdout_stderr),
644+
dirs: Default::default(),
645645
layouts,
646646
threads: ThreadManager::default(),
647647
static_roots: Vec::new(),
@@ -774,11 +774,11 @@ impl VisitProvenance for MiriMachine<'_, '_> {
774774
argv,
775775
cmd_line,
776776
extern_statics,
777-
dir_handler,
777+
dirs,
778778
borrow_tracker,
779779
data_race,
780780
alloc_addresses,
781-
file_handler,
781+
fds,
782782
tcx: _,
783783
isolated_op: _,
784784
validate: _,
@@ -817,8 +817,8 @@ impl VisitProvenance for MiriMachine<'_, '_> {
817817
threads.visit_provenance(visit);
818818
tls.visit_provenance(visit);
819819
env_vars.visit_provenance(visit);
820-
dir_handler.visit_provenance(visit);
821-
file_handler.visit_provenance(visit);
820+
dirs.visit_provenance(visit);
821+
fds.visit_provenance(visit);
822822
data_race.visit_provenance(visit);
823823
borrow_tracker.visit_provenance(visit);
824824
alloc_addresses.visit_provenance(visit);
@@ -1066,7 +1066,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10661066
let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
10671067
if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
10681068
throw_unsup_format!(
1069-
"`extern` static `{name}` from crate `{krate}` has been declared \
1069+
"extern static `{link_name}` has been declared as `{krate}::{name}` \
10701070
with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
10711071
but Miri emulates it via an extern static shim \
10721072
with a size of {shim_size} bytes and alignment of {shim_align} bytes",
@@ -1080,11 +1080,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10801080
}
10811081
Ok(ptr)
10821082
} else {
1083-
throw_unsup_format!(
1084-
"`extern` static `{name}` from crate `{krate}` is not supported by Miri",
1085-
name = ecx.tcx.def_path_str(def_id),
1086-
krate = ecx.tcx.crate_name(def_id.krate),
1087-
)
1083+
throw_unsup_format!("extern static `{link_name}` is not supported by Miri",)
10881084
}
10891085
}
10901086

‎src/tools/miri/src/shims/unix/fd.rs

+431
Large diffs are not rendered by default.

‎src/tools/miri/src/shims/unix/foreign_items.rs

+34-26
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ use rustc_span::Symbol;
66
use rustc_target::abi::{Align, Size};
77
use rustc_target::spec::abi::Abi;
88

9+
use crate::shims::unix::*;
910
use crate::*;
1011
use shims::foreign_items::EmulateForeignItemResult;
11-
use shims::unix::fs::EvalContextExt as _;
12-
use shims::unix::mem::EvalContextExt as _;
13-
use shims::unix::sync::EvalContextExt as _;
14-
use shims::unix::thread::EvalContextExt as _;
1512

1613
use shims::unix::freebsd::foreign_items as freebsd;
1714
use shims::unix::linux::foreign_items as linux;
@@ -51,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
5148
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
5249
#[rustfmt::skip]
5350
match link_name.as_str() {
54-
// Environment related shims
51+
// Environment variables
5552
"getenv" => {
5653
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
5754
let result = this.getenv(name)?;
@@ -79,25 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7976
this.write_scalar(Scalar::from_i32(result), dest)?;
8077
}
8178

82-
// File related shims
83-
"open" | "open64" => {
84-
// `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
85-
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
86-
let result = this.open(args)?;
87-
this.write_scalar(Scalar::from_i32(result), dest)?;
88-
}
89-
"close" => {
90-
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
91-
let result = this.close(fd)?;
92-
this.write_scalar(result, dest)?;
93-
}
94-
"fcntl" => {
95-
// `fcntl` is variadic. The argument count is checked based on the first argument
96-
// in `this.fcntl()`, so we do not use `check_shim` here.
97-
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
98-
let result = this.fcntl(args)?;
99-
this.write_scalar(Scalar::from_i32(result), dest)?;
100-
}
79+
// File descriptors
10180
"read" => {
10281
let [fd, buf, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
10382
let fd = this.read_scalar(fd)?.to_i32()?;
@@ -116,6 +95,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
11695
// Now, `result` is the value we return back to the program.
11796
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
11897
}
98+
"close" => {
99+
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
100+
let result = this.close(fd)?;
101+
this.write_scalar(result, dest)?;
102+
}
103+
"fcntl" => {
104+
// `fcntl` is variadic. The argument count is checked based on the first argument
105+
// in `this.fcntl()`, so we do not use `check_shim` here.
106+
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
107+
let result = this.fcntl(args)?;
108+
this.write_scalar(Scalar::from_i32(result), dest)?;
109+
}
110+
111+
// File and file system access
112+
"open" | "open64" => {
113+
// `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
114+
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
115+
let result = this.open(args)?;
116+
this.write_scalar(Scalar::from_i32(result), dest)?;
117+
}
119118
"unlink" => {
120119
let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
121120
let result = this.unlink(path)?;
@@ -219,7 +218,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
219218
this.write_scalar(Scalar::from_i32(result), dest)?;
220219
}
221220

222-
// Time related shims
221+
// Sockets
222+
"socketpair" => {
223+
let [domain, type_, protocol, sv] =
224+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
225+
226+
let result = this.socketpair(domain, type_, protocol, sv)?;
227+
this.write_scalar(result, dest)?;
228+
}
229+
230+
// Time
223231
"gettimeofday" => {
224232
let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
225233
let result = this.gettimeofday(tv, tz)?;
@@ -598,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
598606
if bufsize > 256 {
599607
let err = this.eval_libc("EIO");
600608
this.set_last_error(err)?;
601-
this.write_scalar(Scalar::from_i32(-1), dest)?
609+
this.write_scalar(Scalar::from_i32(-1), dest)?;
602610
} else {
603611
this.gen_random(buf, bufsize)?;
604612
this.write_scalar(Scalar::from_i32(0), dest)?;

‎src/tools/miri/src/shims/unix/freebsd/foreign_items.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use rustc_span::Symbol;
22
use rustc_target::spec::abi::Abi;
33

4+
use crate::shims::unix::*;
45
use crate::*;
56
use shims::foreign_items::EmulateForeignItemResult;
6-
use shims::unix::fs::EvalContextExt as _;
7-
use shims::unix::thread::EvalContextExt as _;
87

98
pub fn is_dyn_sym(_name: &str) -> bool {
109
false

‎src/tools/miri/src/shims/unix/fs.rs

+100-507
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
1-
use std::cell::Cell;
1+
use std::io;
22

3-
use rustc_middle::ty::ScalarInt;
3+
use rustc_data_structures::fx::FxHashMap;
44

5+
use crate::shims::unix::*;
56
use crate::*;
6-
use epoll::{Epoll, EpollEvent};
7-
use event::Event;
8-
use socketpair::SocketPair;
97

10-
use shims::unix::fs::EvalContextExt as _;
8+
/// An `Epoll` file descriptor connects file handles and epoll events
9+
#[derive(Clone, Debug, Default)]
10+
struct Epoll {
11+
/// The file descriptors we are watching, and what we are watching for.
12+
file_descriptors: FxHashMap<i32, EpollEvent>,
13+
}
14+
15+
/// Epoll Events associate events with data.
16+
/// These fields are currently unused by miri.
17+
/// This matches the `epoll_event` struct defined
18+
/// by the epoll_ctl man page. For more information
19+
/// see the man page:
20+
///
21+
/// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
22+
#[derive(Clone, Debug)]
23+
struct EpollEvent {
24+
#[allow(dead_code)]
25+
events: u32,
26+
/// `Scalar<Provenance>` is used to represent the
27+
/// `epoll_data` type union.
28+
#[allow(dead_code)]
29+
data: Scalar<Provenance>,
30+
}
31+
32+
impl FileDescriptor for Epoll {
33+
fn name(&self) -> &'static str {
34+
"epoll"
35+
}
1136

12-
pub mod epoll;
13-
pub mod event;
14-
pub mod socketpair;
37+
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
38+
// FIXME: this is probably wrong -- check if the `dup`ed descriptor truly uses an
39+
// independent event set.
40+
Ok(Box::new(self.clone()))
41+
}
42+
43+
fn close<'tcx>(
44+
self: Box<Self>,
45+
_communicate_allowed: bool,
46+
) -> InterpResult<'tcx, io::Result<i32>> {
47+
Ok(Ok(0))
48+
}
49+
}
1550

1651
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
1752
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
@@ -35,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3570
throw_unsup_format!("epoll_create1 flags {flags} are not implemented");
3671
}
3772

38-
let fd = this.machine.file_handler.insert_fd(Box::new(Epoll::default()));
73+
let fd = this.machine.fds.insert_fd(Box::new(Epoll::default()));
3974
Ok(Scalar::from_i32(fd))
4075
}
4176

@@ -79,26 +114,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
79114
let data = this.read_scalar(&data)?;
80115
let event = EpollEvent { events, data };
81116

82-
if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
117+
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
83118
let epfd = epfd
84119
.downcast_mut::<Epoll>()
85120
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
86121

87122
epfd.file_descriptors.insert(fd, event);
88123
Ok(Scalar::from_i32(0))
89124
} else {
90-
Ok(Scalar::from_i32(this.handle_not_found()?))
125+
Ok(Scalar::from_i32(this.fd_not_found()?))
91126
}
92127
} else if op == epoll_ctl_del {
93-
if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
128+
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
94129
let epfd = epfd
95130
.downcast_mut::<Epoll>()
96131
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
97132

98133
epfd.file_descriptors.remove(&fd);
99134
Ok(Scalar::from_i32(0))
100135
} else {
101-
Ok(Scalar::from_i32(this.handle_not_found()?))
136+
Ok(Scalar::from_i32(this.fd_not_found()?))
102137
}
103138
} else {
104139
let einval = this.eval_libc("EINVAL");
@@ -150,104 +185,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
150185
let _maxevents = this.read_scalar(maxevents)?.to_i32()?;
151186
let _timeout = this.read_scalar(timeout)?.to_i32()?;
152187

153-
if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
188+
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
154189
let _epfd = epfd
155190
.downcast_mut::<Epoll>()
156191
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
157192

158193
// FIXME return number of events ready when scheme for marking events ready exists
159194
throw_unsup_format!("returning ready events from epoll_wait is not yet implemented");
160195
} else {
161-
Ok(Scalar::from_i32(this.handle_not_found()?))
196+
Ok(Scalar::from_i32(this.fd_not_found()?))
162197
}
163198
}
164-
165-
/// This function creates an `Event` that is used as an event wait/notify mechanism by
166-
/// user-space applications, and by the kernel to notify user-space applications of events.
167-
/// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
168-
/// with the value specified in the `initval` argument.
169-
///
170-
/// A new file descriptor referring to the `Event` is returned. The `read`, `write`, `poll`,
171-
/// `select`, and `close` operations can be performed on the file descriptor. For more
172-
/// information on these operations, see the man page linked below.
173-
///
174-
/// The `flags` are not currently implemented for eventfd.
175-
/// The `flags` may be bitwise ORed to change the behavior of `eventfd`:
176-
/// `EFD_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor.
177-
/// `EFD_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the new open file description.
178-
/// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics.
179-
///
180-
/// <https://linux.die.net/man/2/eventfd>
181-
#[expect(clippy::needless_if)]
182-
fn eventfd(
183-
&mut self,
184-
val: &OpTy<'tcx, Provenance>,
185-
flags: &OpTy<'tcx, Provenance>,
186-
) -> InterpResult<'tcx, Scalar<Provenance>> {
187-
let this = self.eval_context_mut();
188-
189-
let val = this.read_scalar(val)?.to_u32()?;
190-
let flags = this.read_scalar(flags)?.to_i32()?;
191-
192-
let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC");
193-
let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK");
194-
let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE");
195-
196-
if flags & (efd_cloexec | efd_nonblock | efd_semaphore) == 0 {
197-
throw_unsup_format!("{flags} is unsupported");
198-
}
199-
// FIXME handle the cloexec and nonblock flags
200-
if flags & efd_cloexec == efd_cloexec {}
201-
if flags & efd_nonblock == efd_nonblock {}
202-
if flags & efd_semaphore == efd_semaphore {
203-
throw_unsup_format!("EFD_SEMAPHORE is unsupported");
204-
}
205-
206-
let fh = &mut this.machine.file_handler;
207-
let fd = fh.insert_fd(Box::new(Event { val: Cell::new(val.into()) }));
208-
Ok(Scalar::from_i32(fd))
209-
}
210-
211-
/// Currently this function creates new `SocketPair`s without specifying the domain, type, or
212-
/// protocol of the new socket and these are stored in the socket values `sv` argument.
213-
///
214-
/// This function creates an unnamed pair of connected sockets in the specified domain, of the
215-
/// specified type, and using the optionally specified protocol.
216-
///
217-
/// The `domain` argument specified a communication domain; this selects the protocol family
218-
/// used for communication. The socket `type` specifies the communication semantics.
219-
/// The `protocol` specifies a particular protocol to use with the socket. Normally there's
220-
/// only a single protocol supported for a particular socket type within a given protocol
221-
/// family, in which case `protocol` can be specified as 0. It is possible that many protocols
222-
/// exist and in that case, a particular protocol must be specified.
223-
///
224-
/// For more information on the arguments see the socket manpage:
225-
/// <https://linux.die.net/man/2/socket>
226-
///
227-
/// <https://linux.die.net/man/2/socketpair>
228-
fn socketpair(
229-
&mut self,
230-
domain: &OpTy<'tcx, Provenance>,
231-
type_: &OpTy<'tcx, Provenance>,
232-
protocol: &OpTy<'tcx, Provenance>,
233-
sv: &OpTy<'tcx, Provenance>,
234-
) -> InterpResult<'tcx, Scalar<Provenance>> {
235-
let this = self.eval_context_mut();
236-
237-
let _domain = this.read_scalar(domain)?.to_i32()?;
238-
let _type_ = this.read_scalar(type_)?.to_i32()?;
239-
let _protocol = this.read_scalar(protocol)?.to_i32()?;
240-
let sv = this.deref_pointer(sv)?;
241-
242-
let fh = &mut this.machine.file_handler;
243-
let sv0 = fh.insert_fd(Box::new(SocketPair));
244-
let sv0 = ScalarInt::try_from_int(sv0, sv.layout.size).unwrap();
245-
let sv1 = fh.insert_fd(Box::new(SocketPair));
246-
let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap();
247-
248-
this.write_scalar(sv0, &sv)?;
249-
this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?;
250-
251-
Ok(Scalar::from_i32(0))
252-
}
253199
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! Linux `eventfd` implementation.
2+
//! Currently just a stub.
3+
use std::cell::Cell;
4+
use std::io;
5+
6+
use rustc_middle::ty::TyCtxt;
7+
use rustc_target::abi::Endian;
8+
9+
use crate::shims::unix::*;
10+
use crate::*;
11+
12+
/// A kind of file descriptor created by `eventfd`.
13+
/// The `Event` type isn't currently written to by `eventfd`.
14+
/// The interface is meant to keep track of objects associated
15+
/// with a file descriptor. For more information see the man
16+
/// page below:
17+
///
18+
/// <https://man.netbsd.org/eventfd.2>
19+
#[derive(Debug)]
20+
struct Event {
21+
/// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
22+
/// kernel. This counter is initialized with the value specified in the argument initval.
23+
val: Cell<u64>,
24+
}
25+
26+
impl FileDescriptor for Event {
27+
fn name(&self) -> &'static str {
28+
"event"
29+
}
30+
31+
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
32+
// FIXME: this is wrong, the new and old FD should refer to the same event object!
33+
Ok(Box::new(Event { val: self.val.clone() }))
34+
}
35+
36+
fn close<'tcx>(
37+
self: Box<Self>,
38+
_communicate_allowed: bool,
39+
) -> InterpResult<'tcx, io::Result<i32>> {
40+
Ok(Ok(0))
41+
}
42+
43+
/// A write call adds the 8-byte integer value supplied in
44+
/// its buffer (in native endianness) to the counter. The maximum value that may be
45+
/// stored in the counter is the largest unsigned 64-bit value
46+
/// minus 1 (i.e., 0xfffffffffffffffe). If the addition would
47+
/// cause the counter's value to exceed the maximum, then the
48+
/// write either blocks until a read is performed on the
49+
/// file descriptor, or fails with the error EAGAIN if the
50+
/// file descriptor has been made nonblocking.
51+
52+
/// A write fails with the error EINVAL if the size of the
53+
/// supplied buffer is less than 8 bytes, or if an attempt is
54+
/// made to write the value 0xffffffffffffffff.
55+
fn write<'tcx>(
56+
&self,
57+
_communicate_allowed: bool,
58+
bytes: &[u8],
59+
tcx: TyCtxt<'tcx>,
60+
) -> InterpResult<'tcx, io::Result<usize>> {
61+
let v1 = self.val.get();
62+
let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
63+
// Convert from target endianness to host endianness.
64+
let num = match tcx.sess.target.endian {
65+
Endian::Little => u64::from_le_bytes(bytes),
66+
Endian::Big => u64::from_be_bytes(bytes),
67+
};
68+
// FIXME handle blocking when addition results in exceeding the max u64 value
69+
// or fail with EAGAIN if the file descriptor is nonblocking.
70+
let v2 = v1.checked_add(num).unwrap();
71+
self.val.set(v2);
72+
assert_eq!(8, bytes.len());
73+
Ok(Ok(8))
74+
}
75+
}
76+
77+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
78+
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
79+
/// This function creates an `Event` that is used as an event wait/notify mechanism by
80+
/// user-space applications, and by the kernel to notify user-space applications of events.
81+
/// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
82+
/// with the value specified in the `initval` argument.
83+
///
84+
/// A new file descriptor referring to the `Event` is returned. The `read`, `write`, `poll`,
85+
/// `select`, and `close` operations can be performed on the file descriptor. For more
86+
/// information on these operations, see the man page linked below.
87+
///
88+
/// The `flags` are not currently implemented for eventfd.
89+
/// The `flags` may be bitwise ORed to change the behavior of `eventfd`:
90+
/// `EFD_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor.
91+
/// `EFD_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the new open file description.
92+
/// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics.
93+
///
94+
/// <https://linux.die.net/man/2/eventfd>
95+
fn eventfd(
96+
&mut self,
97+
val: &OpTy<'tcx, Provenance>,
98+
flags: &OpTy<'tcx, Provenance>,
99+
) -> InterpResult<'tcx, Scalar<Provenance>> {
100+
let this = self.eval_context_mut();
101+
102+
let val = this.read_scalar(val)?.to_u32()?;
103+
let flags = this.read_scalar(flags)?.to_i32()?;
104+
105+
let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC");
106+
let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK");
107+
let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE");
108+
109+
if flags & (efd_cloexec | efd_nonblock | efd_semaphore) != flags {
110+
throw_unsup_format!("eventfd: flag {flags:#x} is unsupported");
111+
}
112+
if flags & efd_cloexec == efd_cloexec {
113+
// cloexec does nothing as we don't support `exec`
114+
}
115+
if flags & efd_nonblock == efd_nonblock {
116+
// FIXME remember the nonblock flag
117+
}
118+
if flags & efd_semaphore == efd_semaphore {
119+
throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported");
120+
}
121+
122+
let fd = this.machine.fds.insert_fd(Box::new(Event { val: Cell::new(val.into()) }));
123+
Ok(Scalar::from_i32(fd))
124+
}
125+
}

‎src/tools/miri/src/shims/unix/linux/fd/epoll.rs

-47
This file was deleted.

‎src/tools/miri/src/shims/unix/linux/fd/event.rs

-72
This file was deleted.

‎src/tools/miri/src/shims/unix/linux/fd/socketpair.rs

-28
This file was deleted.

‎src/tools/miri/src/shims/unix/linux/foreign_items.rs

+33-44
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ use rustc_target::spec::abi::Abi;
33

44
use crate::machine::SIGRTMAX;
55
use crate::machine::SIGRTMIN;
6+
use crate::shims::unix::*;
67
use crate::*;
78
use shims::foreign_items::EmulateForeignItemResult;
8-
use shims::unix::fs::EvalContextExt as _;
9-
use shims::unix::linux::fd::EvalContextExt as _;
9+
use shims::unix::linux::epoll::EvalContextExt as _;
10+
use shims::unix::linux::eventfd::EvalContextExt as _;
1011
use shims::unix::linux::mem::EvalContextExt as _;
1112
use shims::unix::linux::sync::futex;
12-
use shims::unix::mem::EvalContextExt as _;
13-
use shims::unix::sync::EvalContextExt as _;
14-
use shims::unix::thread::EvalContextExt as _;
1513

1614
pub fn is_dyn_sym(name: &str) -> bool {
1715
matches!(name, "getrandom")
@@ -31,34 +29,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3129
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
3230

3331
match link_name.as_str() {
34-
// errno
35-
"__errno_location" => {
36-
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
37-
let errno_place = this.last_error_place()?;
38-
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
39-
}
40-
4132
// File related shims (but also see "syscall" below for statx)
4233
"readdir64" => {
4334
let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
4435
let result = this.linux_readdir64(dirp)?;
4536
this.write_scalar(result, dest)?;
4637
}
47-
"mmap64" => {
48-
let [addr, length, prot, flags, fd, offset] =
49-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
50-
let offset = this.read_scalar(offset)?.to_i64()?;
51-
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
52-
this.write_scalar(ptr, dest)?;
53-
}
54-
55-
// Linux-only
5638
"sync_file_range" => {
5739
let [fd, offset, nbytes, flags] =
5840
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
5941
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
6042
this.write_scalar(result, dest)?;
6143
}
44+
45+
// epoll, eventfd
6246
"epoll_create1" => {
6347
let [flag] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
6448
let result = this.epoll_create1(flag)?;
@@ -82,29 +66,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8266
let result = this.eventfd(val, flag)?;
8367
this.write_scalar(result, dest)?;
8468
}
85-
"mremap" => {
86-
let [old_address, old_size, new_size, flags] =
87-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
88-
let ptr = this.mremap(old_address, old_size, new_size, flags)?;
89-
this.write_scalar(ptr, dest)?;
90-
}
91-
"socketpair" => {
92-
let [domain, type_, protocol, sv] =
93-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
94-
95-
let result = this.socketpair(domain, type_, protocol, sv)?;
96-
this.write_scalar(result, dest)?;
97-
}
98-
"__libc_current_sigrtmin" => {
99-
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
100-
101-
this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?;
102-
}
103-
"__libc_current_sigrtmax" => {
104-
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
105-
106-
this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
107-
}
10869

10970
// Threading
11071
"pthread_condattr_setclock" => {
@@ -206,6 +167,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
206167
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
207168
getrandom(this, ptr, len, flags, dest)?;
208169
}
170+
"mmap64" => {
171+
let [addr, length, prot, flags, fd, offset] =
172+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
173+
let offset = this.read_scalar(offset)?.to_i64()?;
174+
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
175+
this.write_scalar(ptr, dest)?;
176+
}
177+
"mremap" => {
178+
let [old_address, old_size, new_size, flags] =
179+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
180+
let ptr = this.mremap(old_address, old_size, new_size, flags)?;
181+
this.write_scalar(ptr, dest)?;
182+
}
183+
"__errno_location" => {
184+
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
185+
let errno_place = this.last_error_place()?;
186+
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
187+
}
188+
"__libc_current_sigrtmin" => {
189+
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
190+
191+
this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?;
192+
}
193+
"__libc_current_sigrtmax" => {
194+
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
195+
196+
this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
197+
}
209198

210199
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
211200
// These shims are enabled only when the caller is in the standard library.
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
pub mod fd;
1+
pub mod epoll;
2+
pub mod eventfd;
23
pub mod foreign_items;
34
pub mod mem;
45
pub mod sync;

‎src/tools/miri/src/shims/unix/macos/foreign_items.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use rustc_span::Symbol;
22
use rustc_target::spec::abi::Abi;
33

4+
use crate::shims::unix::*;
45
use crate::*;
56
use shims::foreign_items::EmulateForeignItemResult;
6-
use shims::unix::fs::EvalContextExt as _;
7-
use shims::unix::thread::EvalContextExt as _;
87

98
pub fn is_dyn_sym(_name: &str) -> bool {
109
false

‎src/tools/miri/src/shims/unix/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
pub mod foreign_items;
22

3+
mod fd;
34
mod fs;
45
mod mem;
6+
mod socket;
57
mod sync;
68
mod thread;
79

810
mod freebsd;
911
mod linux;
1012
mod macos;
1113

12-
pub use fs::{DirHandler, FileHandler};
14+
pub use fd::{FdTable, FileDescriptor};
15+
pub use fs::DirTable;
16+
// All the unix-specific extension traits
17+
pub use fd::EvalContextExt as _;
18+
pub use fs::EvalContextExt as _;
19+
pub use mem::EvalContextExt as _;
20+
pub use socket::EvalContextExt as _;
21+
pub use sync::EvalContextExt as _;
22+
pub use thread::EvalContextExt as _;
1323

1424
// Make up some constants.
1525
const UID: u32 = 1000;
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::io;
2+
3+
use crate::shims::unix::*;
4+
use crate::*;
5+
6+
/// Pair of connected sockets.
7+
///
8+
/// We currently don't allow sending any data through this pair, so this can be just a dummy.
9+
#[derive(Debug)]
10+
struct SocketPair;
11+
12+
impl FileDescriptor for SocketPair {
13+
fn name(&self) -> &'static str {
14+
"socketpair"
15+
}
16+
17+
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
18+
Ok(Box::new(SocketPair))
19+
}
20+
21+
fn close<'tcx>(
22+
self: Box<Self>,
23+
_communicate_allowed: bool,
24+
) -> InterpResult<'tcx, io::Result<i32>> {
25+
Ok(Ok(0))
26+
}
27+
}
28+
29+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
30+
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
31+
/// Currently this function this function is a stub. Eventually we need to
32+
/// properly implement an FD type for sockets and have this function create
33+
/// two sockets and associated FDs such that writing to one will produce
34+
/// data that can be read from the other.
35+
///
36+
/// For more information on the arguments see the socketpair manpage:
37+
/// <https://linux.die.net/man/2/socketpair>
38+
fn socketpair(
39+
&mut self,
40+
domain: &OpTy<'tcx, Provenance>,
41+
type_: &OpTy<'tcx, Provenance>,
42+
protocol: &OpTy<'tcx, Provenance>,
43+
sv: &OpTy<'tcx, Provenance>,
44+
) -> InterpResult<'tcx, Scalar<Provenance>> {
45+
let this = self.eval_context_mut();
46+
47+
let _domain = this.read_scalar(domain)?.to_i32()?;
48+
let _type_ = this.read_scalar(type_)?.to_i32()?;
49+
let _protocol = this.read_scalar(protocol)?.to_i32()?;
50+
let sv = this.deref_pointer(sv)?;
51+
52+
// FIXME: fail on unsupported inputs
53+
54+
let fds = &mut this.machine.fds;
55+
let sv0 = fds.insert_fd(Box::new(SocketPair));
56+
let sv0 = Scalar::try_from_int(sv0, sv.layout.size).unwrap();
57+
let sv1 = fds.insert_fd(Box::new(SocketPair));
58+
let sv1 = Scalar::try_from_int(sv1, sv.layout.size).unwrap();
59+
60+
this.write_scalar(sv0, &sv)?;
61+
this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?;
62+
63+
Ok(Scalar::from_i32(0))
64+
}
65+
}

‎src/tools/miri/test-cargo-miri/run-test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ def cargo_miri(cmd, quiet = True):
3131

3232
def normalize_stdout(str):
3333
str = str.replace("src\\", "src/") # normalize paths across platforms
34-
str = re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) # the time keeps changing, obviously
34+
str = re.sub("finished in \\d+\\.\\d\\ds", "finished in $TIME", str) # the time keeps changing, obviously
3535
return str
3636

3737
def normalize_stderr(str):
38-
str = re.sub("Preparing a sysroot for Miri \(target: [a-z0-9_-]+\)\.\.\. done\n", "", str) # remove leading cargo-miri setup output
38+
str = re.sub("Preparing a sysroot for Miri \\(target: [a-z0-9_-]+\\)\\.\\.\\. done\n", "", str) # remove leading cargo-miri setup output
3939
return str
4040

4141
def check_output(actual, path, name):

‎src/tools/miri/tests/extern-so/libcode.version

-9
This file was deleted.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CODEABI_1.0 {
2+
# Define which symbols to export.
3+
global:
4+
add_one_int;
5+
printer;
6+
test_stack_spill;
7+
get_unsigned_int;
8+
add_int16;
9+
add_short_to_long;
10+
# The rest remains private.
11+
local: *;
12+
};

‎src/tools/miri/tests/fail/extern_static.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: `extern` static `FOO` from crate `extern_static` is not supported by Miri
1+
error: unsupported operation: extern static `FOO` is not supported by Miri
22
--> $DIR/extern_static.rs:LL:CC
33
|
44
LL | let _val = unsafe { std::ptr::addr_of!(FOO) };
5-
| ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri
5+
| ^^^ extern static `FOO` is not supported by Miri
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
88
= note: BACKTRACE:

‎src/tools/miri/tests/fail/extern_static_in_const.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: `extern` static `E` from crate `extern_static_in_const` is not supported by Miri
1+
error: unsupported operation: extern static `E` is not supported by Miri
22
--> $DIR/extern_static_in_const.rs:LL:CC
33
|
44
LL | let _val = X;
5-
| ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri
5+
| ^ extern static `E` is not supported by Miri
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
88
= note: BACKTRACE:

‎src/tools/miri/tests/fail/extern_static_wrong_size.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ extern "C" {
66
}
77

88
fn main() {
9-
let _val = unsafe { environ }; //~ ERROR: /has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/
9+
let _val = unsafe { environ }; //~ ERROR: /with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/
1010
}

‎src/tools/miri/tests/fail/extern_static_wrong_size.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
1+
error: unsupported operation: extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
22
--> $DIR/extern_static_wrong_size.rs:LL:CC
33
|
44
LL | let _val = unsafe { environ };
5-
| ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
5+
| ^^^^^^^ extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
88
= note: BACKTRACE:

‎src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri
1+
error: unsupported operation: extern static `_dispatch_queue_attr_concurrent` is not supported by Miri
22
--> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC
33
|
44
LL | let _val = *DISPATCH_QUEUE_CONCURRENT;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ extern static `_dispatch_queue_attr_concurrent` is not supported by Miri
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
88
= note: BACKTRACE:

‎src/tools/miri/tests/fail/tree_borrows/spurious_read.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ fn retagx_retagy_retx_writey_rety() {
8989
// - retag `y` protected
9090
// - (wait for the other thread to return so that there is no foreign protector when we write)
9191
// - attempt a write through `y`.
92-
// - (UB should have occured by now, but the next step would be to
92+
// - (UB should have occurred by now, but the next step would be to
9393
// remove `y`'s protector)
9494
let thread_y = thread::spawn(move || {
9595
let b = (2, by);

‎src/tools/miri/tests/ui.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use colored::*;
2-
use regex::bytes::Regex;
31
use std::ffi::OsString;
42
use std::num::NonZeroUsize;
53
use std::path::{Path, PathBuf};
64
use std::{env, process::Command};
5+
6+
use colored::*;
7+
use regex::bytes::Regex;
78
use ui_test::color_eyre::eyre::{Context, Result};
89
use ui_test::{
910
status_emitter, CommandBuilder, Config, Format, Match, Mode, OutputConflictHandling,
@@ -44,12 +45,15 @@ fn build_so_for_c_ffi_tests() -> PathBuf {
4445
// This is to avoid automatically adding `malloc`, etc.
4546
// Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
4647
"-fPIC",
47-
"-Wl,--version-script=tests/extern-so/libcode.version",
48+
"-Wl,--version-script=tests/extern-so/libtest.map",
4849
])
4950
.output()
5051
.expect("failed to generate shared object file for testing external C function calls");
5152
if !cc_output.status.success() {
52-
panic!("error in generating shared object file for testing external C function calls");
53+
panic!(
54+
"error in generating shared object file for testing external C function calls:\n{}",
55+
String::from_utf8_lossy(&cc_output.stderr),
56+
);
5357
}
5458
so_file_path
5559
}
@@ -120,10 +124,10 @@ fn run_tests(
120124
config.program.args.push("--target".into());
121125
config.program.args.push(target.into());
122126

123-
// If we're on linux, and we're testing the extern-so functionality,
124-
// then build the shared object file for testing external C function calls
125-
// and push the relevant compiler flag.
126-
if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
127+
// If we're testing the extern-so functionality, then build the shared object file for testing
128+
// external C function calls and push the relevant compiler flag.
129+
if path.starts_with("tests/extern-so/") {
130+
assert!(cfg!(target_os = "linux"));
127131
let so_file_path = build_so_for_c_ffi_tests();
128132
let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
129133
flag.push(so_file_path.into_os_string());

‎tests/incremental/spike-neg1.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
//@ revisions:rpass1 rpass2
99
//@ should-fail
10+
//@ compile-flags: -Z query-dep-graph
1011

1112
#![feature(rustc_attrs)]
1213

‎tests/incremental/spike-neg2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
//@ revisions:rpass1 rpass2
99
//@ should-fail
10+
//@ compile-flags: -Z query-dep-graph
1011

1112
#![feature(rustc_attrs)]
1213

‎tests/rustdoc-gui/search-result-color.goml

+159-294
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.