Skip to content

Commit 9a1d156

Browse files
committed
Auto merge of #135742 - RalfJung:miri-sync, r=RalfJung
Miri subtree update r? `@ghost`
2 parents 39dc268 + 49375c4 commit 9a1d156

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+982
-765
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ jobs:
126126
with:
127127
fetch-depth: 256 # get a bit more of the history
128128
- name: install josh-proxy
129-
run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
129+
run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
130130
- name: setup bot git name and email
131131
run: |
132132
git config --global user.name 'The Miri Cronjob Bot'

src/tools/miri/CONTRIBUTING.md

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

292292
```sh
293-
RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
293+
cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
294294
```
295295

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

src/tools/miri/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ degree documented below):
217217
- For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
218218
make no promises and we don't run tests for such targets.
219219
- We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
220-
- `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`.
221-
- `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
220+
- `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
221+
- `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
222222
- `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
223223
- `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
224224
- For targets on other operating systems, Miri might fail before even reaching the `main` function.

src/tools/miri/ci/ci.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,14 @@ case $HOST_TARGET in
147147
# Extra tier 2
148148
TEST_TARGET=arm-unknown-linux-gnueabi run_tests
149149
TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
150+
# Not officially supported tier 2
151+
TEST_TARGET=x86_64-unknown-illumos run_tests
152+
TEST_TARGET=x86_64-pc-solaris run_tests
150153
# Partially supported targets (tier 2)
151154
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
152155
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
153156
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
154157
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
155-
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
156-
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
157158
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread epoll eventfd
158159
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
159160
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std

src/tools/miri/etc/rust_analyzer_vscode.json

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,19 @@
55
"cargo-miri/Cargo.toml",
66
"miri-script/Cargo.toml",
77
],
8-
"rust-analyzer.check.invocationLocation": "root",
98
"rust-analyzer.check.invocationStrategy": "once",
109
"rust-analyzer.check.overrideCommand": [
11-
"env",
12-
"MIRI_AUTO_OPS=no",
1310
"./miri",
1411
"clippy", // make this `check` when working with a locally built rustc
1512
"--message-format=json",
1613
],
14+
"rust-analyzer.cargo.extraEnv": {
15+
"MIRI_AUTO_OPS": "no",
16+
"MIRI_IN_RA": "1",
17+
},
1718
// Contrary to what the name suggests, this also affects proc macros.
18-
"rust-analyzer.cargo.buildScripts.invocationLocation": "root",
1919
"rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
2020
"rust-analyzer.cargo.buildScripts.overrideCommand": [
21-
"env",
22-
"MIRI_AUTO_OPS=no",
2321
"./miri",
2422
"check",
2523
"--message-format=json",

src/tools/miri/miri

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ set -e
33
# We want to call the binary directly, so we need to know where it ends up.
44
ROOT_DIR="$(dirname "$0")"
55
MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target
6-
# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
7-
if ! [ -t 1 ] && [ -z "$CI" ]; then
6+
TOOLCHAIN="+nightly"
7+
# If we are being invoked for RA, use JSON output and the default toolchain (to make proc-macros
8+
# work in RA). This needs a different target dir to avoid mixing up the builds.
9+
if [ -n "$MIRI_IN_RA" ]; then
810
MESSAGE_FORMAT="--message-format=json"
11+
TOOLCHAIN=""
12+
MIRI_SCRIPT_TARGET_DIR="$MIRI_SCRIPT_TARGET_DIR"/ra
913
fi
1014
# We need a nightly toolchain, for `-Zroot-dir`.
11-
cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
15+
cargo $TOOLCHAIN build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
1216
-Zroot-dir="$ROOT_DIR" \
1317
-q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
1418
( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 )

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ impl Command {
423423
.map(|path| path.into_os_string().into_string().unwrap())
424424
.collect()
425425
} else {
426-
benches.into_iter().map(Into::into).collect()
426+
benches.into_iter().collect()
427427
};
428428
let target_flag = if let Some(target) = target {
429429
let mut flag = OsString::from("--target=");
@@ -564,6 +564,10 @@ impl Command {
564564
if bless {
565565
e.sh.set_var("RUSTC_BLESS", "Gesundheit");
566566
}
567+
if e.sh.var("MIRI_TEST_TARGET").is_ok() {
568+
// Avoid trouble due to an incorrectly set env var.
569+
bail!("MIRI_TEST_TARGET must not be set when invoking `./miri test`");
570+
}
567571
if let Some(target) = target {
568572
// Tell the harness which target to test.
569573
e.sh.set_var("MIRI_TEST_TARGET", target);

src/tools/miri/miri-script/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub enum Command {
111111
/// `rustup-toolchain-install-master` must be installed for this to work.
112112
Toolchain {
113113
/// Flags that are passed through to `rustup-toolchain-install-master`.
114+
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
114115
flags: Vec<String>,
115116
},
116117
/// Pull and merge Miri changes from the rustc repo.

src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
13170cd787cb733ed24842ee825bcbd98dc01476
1+
01706e1a34c87656fcbfce198608f4cd2ac6461a

src/tools/miri/src/concurrency/cpu_affinity.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,17 @@ impl CpuAffinityMask {
5454
let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
5555
let offset = cpu % 32;
5656
*chunk = match target.options.endian {
57-
Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
58-
Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
57+
Endian::Little => (u32::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
58+
Endian::Big => (u32::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
5959
};
6060
}
6161
8 => {
6262
let start = cpu / 64 * 8; // first byte of the correct u64
6363
let chunk = self.0[start..].first_chunk_mut::<8>().unwrap();
6464
let offset = cpu % 64;
6565
*chunk = match target.options.endian {
66-
Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
67-
Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
66+
Endian::Little => (u64::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
67+
Endian::Big => (u64::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
6868
};
6969
}
7070
other => bug!("chunk size not supported: {other}"),

src/tools/miri/src/concurrency/sync.rs

+51-39
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
422422
mutex_ref: MutexRef,
423423
retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
424424
}
425-
@unblock = |this| {
425+
|this, unblock: UnblockKind| {
426+
assert_eq!(unblock, UnblockKind::Ready);
427+
426428
assert!(!this.mutex_is_locked(&mutex_ref));
427429
this.mutex_lock(&mutex_ref);
428430

@@ -538,7 +540,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
538540
retval: Scalar,
539541
dest: MPlaceTy<'tcx>,
540542
}
541-
@unblock = |this| {
543+
|this, unblock: UnblockKind| {
544+
assert_eq!(unblock, UnblockKind::Ready);
542545
this.rwlock_reader_lock(id);
543546
this.write_scalar(retval, &dest)?;
544547
interp_ok(())
@@ -623,7 +626,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
623626
retval: Scalar,
624627
dest: MPlaceTy<'tcx>,
625628
}
626-
@unblock = |this| {
629+
|this, unblock: UnblockKind| {
630+
assert_eq!(unblock, UnblockKind::Ready);
627631
this.rwlock_writer_lock(id);
628632
this.write_scalar(retval, &dest)?;
629633
interp_ok(())
@@ -677,25 +681,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
677681
retval_timeout: Scalar,
678682
dest: MPlaceTy<'tcx>,
679683
}
680-
@unblock = |this| {
681-
// The condvar was signaled. Make sure we get the clock for that.
682-
if let Some(data_race) = &this.machine.data_race {
683-
data_race.acquire_clock(
684-
&this.machine.sync.condvars[condvar].clock,
685-
&this.machine.threads,
686-
);
684+
|this, unblock: UnblockKind| {
685+
match unblock {
686+
UnblockKind::Ready => {
687+
// The condvar was signaled. Make sure we get the clock for that.
688+
if let Some(data_race) = &this.machine.data_race {
689+
data_race.acquire_clock(
690+
&this.machine.sync.condvars[condvar].clock,
691+
&this.machine.threads,
692+
);
693+
}
694+
// Try to acquire the mutex.
695+
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
696+
this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
697+
}
698+
UnblockKind::TimedOut => {
699+
// We have to remove the waiter from the queue again.
700+
let thread = this.active_thread();
701+
let waiters = &mut this.machine.sync.condvars[condvar].waiters;
702+
waiters.retain(|waiter| *waiter != thread);
703+
// Now get back the lock.
704+
this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
705+
}
687706
}
688-
// Try to acquire the mutex.
689-
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
690-
this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
691-
}
692-
@timeout = |this| {
693-
// We have to remove the waiter from the queue again.
694-
let thread = this.active_thread();
695-
let waiters = &mut this.machine.sync.condvars[condvar].waiters;
696-
waiters.retain(|waiter| *waiter != thread);
697-
// Now get back the lock.
698-
this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
699707
}
700708
),
701709
);
@@ -752,25 +760,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
752760
dest: MPlaceTy<'tcx>,
753761
errno_timeout: IoError,
754762
}
755-
@unblock = |this| {
756-
let futex = futex_ref.0.borrow();
757-
// Acquire the clock of the futex.
758-
if let Some(data_race) = &this.machine.data_race {
759-
data_race.acquire_clock(&futex.clock, &this.machine.threads);
763+
|this, unblock: UnblockKind| {
764+
match unblock {
765+
UnblockKind::Ready => {
766+
let futex = futex_ref.0.borrow();
767+
// Acquire the clock of the futex.
768+
if let Some(data_race) = &this.machine.data_race {
769+
data_race.acquire_clock(&futex.clock, &this.machine.threads);
770+
}
771+
// Write the return value.
772+
this.write_scalar(retval_succ, &dest)?;
773+
interp_ok(())
774+
},
775+
UnblockKind::TimedOut => {
776+
// Remove the waiter from the futex.
777+
let thread = this.active_thread();
778+
let mut futex = futex_ref.0.borrow_mut();
779+
futex.waiters.retain(|waiter| waiter.thread != thread);
780+
// Set errno and write return value.
781+
this.set_last_error(errno_timeout)?;
782+
this.write_scalar(retval_timeout, &dest)?;
783+
interp_ok(())
784+
},
760785
}
761-
// Write the return value.
762-
this.write_scalar(retval_succ, &dest)?;
763-
interp_ok(())
764-
}
765-
@timeout = |this| {
766-
// Remove the waiter from the futex.
767-
let thread = this.active_thread();
768-
let mut futex = futex_ref.0.borrow_mut();
769-
futex.waiters.retain(|waiter| waiter.thread != thread);
770-
// Set errno and write return value.
771-
this.set_last_error(errno_timeout)?;
772-
this.write_scalar(retval_timeout, &dest)?;
773-
interp_ok(())
774786
}
775787
),
776788
);

src/tools/miri/src/concurrency/thread.rs

+16-67
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::concurrency::data_race;
1919
use crate::shims::tls;
2020
use crate::*;
2121

22-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22+
#[derive(Clone, Copy, Debug, PartialEq)]
2323
enum SchedulingAction {
2424
/// Execute step on the active thread.
2525
ExecuteStep,
@@ -30,6 +30,7 @@ enum SchedulingAction {
3030
}
3131

3232
/// What to do with TLS allocations from terminated threads
33+
#[derive(Clone, Copy, Debug, PartialEq)]
3334
pub enum TlsAllocAction {
3435
/// Deallocate backing memory of thread-local statics as usual
3536
Deallocate,
@@ -38,71 +39,18 @@ pub enum TlsAllocAction {
3839
Leak,
3940
}
4041

41-
/// Trait for callbacks that are executed when a thread gets unblocked.
42-
pub trait UnblockCallback<'tcx>: VisitProvenance {
43-
/// Will be invoked when the thread was unblocked the "regular" way,
44-
/// i.e. whatever event it was blocking on has happened.
45-
fn unblock(self: Box<Self>, ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx>;
46-
47-
/// Will be invoked when the timeout ellapsed without the event the
48-
/// thread was blocking on having occurred.
49-
fn timeout(self: Box<Self>, _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>)
50-
-> InterpResult<'tcx>;
42+
/// The argument type for the "unblock" callback, indicating why the thread got unblocked.
43+
#[derive(Clone, Copy, Debug, PartialEq)]
44+
pub enum UnblockKind {
45+
/// Operation completed successfully, thread continues normal execution.
46+
Ready,
47+
/// The operation did not complete within its specified duration.
48+
TimedOut,
5149
}
52-
pub type DynUnblockCallback<'tcx> = Box<dyn UnblockCallback<'tcx> + 'tcx>;
53-
54-
#[macro_export]
55-
macro_rules! callback {
56-
(
57-
@capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
58-
@unblock = |$this:ident| $unblock:block
59-
) => {
60-
callback!(
61-
@capture<$tcx, $($lft),*> { $($name: $type),* }
62-
@unblock = |$this| $unblock
63-
@timeout = |_this| {
64-
unreachable!(
65-
"timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)"
66-
)
67-
}
68-
)
69-
};
70-
(
71-
@capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
72-
@unblock = |$this:ident| $unblock:block
73-
@timeout = |$this_timeout:ident| $timeout:block
74-
) => {{
75-
struct Callback<$tcx, $($lft),*> {
76-
$($name: $type,)*
77-
_phantom: std::marker::PhantomData<&$tcx ()>,
78-
}
79-
80-
impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
81-
#[allow(unused_variables)]
82-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
83-
$(
84-
self.$name.visit_provenance(visit);
85-
)*
86-
}
87-
}
88-
89-
impl<$tcx, $($lft),*> UnblockCallback<$tcx> for Callback<$tcx, $($lft),*> {
90-
fn unblock(self: Box<Self>, $this: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
91-
#[allow(unused_variables)]
92-
let Callback { $($name,)* _phantom } = *self;
93-
$unblock
94-
}
9550

96-
fn timeout(self: Box<Self>, $this_timeout: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
97-
#[allow(unused_variables)]
98-
let Callback { $($name,)* _phantom } = *self;
99-
$timeout
100-
}
101-
}
102-
103-
Box::new(Callback { $($name,)* _phantom: std::marker::PhantomData })
104-
}}
105-
}
51+
/// Type alias for unblock callbacks, i.e. machine callbacks invoked when
52+
/// a thread gets unblocked.
53+
pub type DynUnblockCallback<'tcx> = DynMachineCallback<'tcx, UnblockKind>;
10654

10755
/// A thread identifier.
10856
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -656,7 +604,8 @@ impl<'tcx> ThreadManager<'tcx> {
656604
@capture<'tcx> {
657605
joined_thread_id: ThreadId,
658606
}
659-
@unblock = |this| {
607+
|this, unblock: UnblockKind| {
608+
assert_eq!(unblock, UnblockKind::Ready);
660609
if let Some(data_race) = &mut this.machine.data_race {
661610
data_race.thread_joined(&this.machine.threads, joined_thread_id);
662611
}
@@ -842,7 +791,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
842791
// 2. Make the scheduler the only place that can change the active
843792
// thread.
844793
let old_thread = this.machine.threads.set_active_thread_id(thread);
845-
callback.timeout(this)?;
794+
callback.call(this, UnblockKind::TimedOut)?;
846795
this.machine.threads.set_active_thread_id(old_thread);
847796
}
848797
// found_callback can remain None if the computer's clock
@@ -1084,7 +1033,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10841033
};
10851034
// The callback must be executed in the previously blocked thread.
10861035
let old_thread = this.machine.threads.set_active_thread_id(thread);
1087-
callback.unblock(this)?;
1036+
callback.call(this, UnblockKind::Ready)?;
10881037
this.machine.threads.set_active_thread_id(old_thread);
10891038
interp_ok(())
10901039
}

0 commit comments

Comments
 (0)